[0.6.239] Fix memory leak
[platform/core/multimedia/libmm-player.git] / src / mm_player_priv.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 /*===========================================================================================
24 |                                                                                                                                                                                       |
25 |  INCLUDE FILES                                                                                                                                                        |
26 |                                                                                                                                                                                       |
27 ========================================================================================== */
28 #include <glib.h>
29 #include <gst/gst.h>
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <sys/time.h>
36 #include <stdlib.h>
37 #include <dlog.h>
38 #include <gio/gio.h>
39
40 #include <mm_error.h>
41 #include <mm_attrs.h>
42 #include <mm_sound.h>
43
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
51
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
56
57 /*===========================================================================================
58 |                                                                                                                                                                                       |
59 |  LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE                                                                                        |
60 |                                                                                                                                                                                       |
61 ========================================================================================== */
62
63 /*---------------------------------------------------------------------------
64 |    GLOBAL CONSTANT DEFINITIONS:                                                                                       |
65 ---------------------------------------------------------------------------*/
66
67 /*---------------------------------------------------------------------------
68 |    IMPORTED VARIABLE DECLARATIONS:                                                                            |
69 ---------------------------------------------------------------------------*/
70
71 /*---------------------------------------------------------------------------
72 |    IMPORTED FUNCTION DECLARATIONS:                                                                            |
73 ---------------------------------------------------------------------------*/
74
75 /*---------------------------------------------------------------------------
76 |    LOCAL #defines:                                                                                                            |
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX   2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN   0.0
80
81 #define MM_VOLUME_FACTOR_DEFAULT                1.0
82 #define MM_VOLUME_FACTOR_MIN                    0
83 #define MM_VOLUME_FACTOR_MAX                    1.0
84
85 /* Don't need to sleep for sound fadeout
86  * fadeout related function will be deleted(Deprecated)
87  */
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT  0
89
90 #define DEFAULT_PLAYBACK_RATE                   1.0
91
92 #define PLAYER_DISPLAY_MODE_DST_ROI             5
93
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
95
96 #define PLAYER_SPHERICAL_DEFAULT_YAW   0  /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
100
101 #define SPATIAL_AUDIO_CAPS             "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO   "http://tizen.org/feature/multimedia.player.spherical_video"
103
104 #define FAKE_SINK_MAX_LATENESS         G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
105
106 #define DEFAULT_PCM_OUT_FORMAT         "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE     44100
108 #define DEFAULT_PCM_OUT_CHANNEL        2
109
110 /*---------------------------------------------------------------------------
111 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
112 ---------------------------------------------------------------------------*/
113
114 /*---------------------------------------------------------------------------
115 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118  We are defining our own and will be removed when it actually exposed */
119 typedef enum {
120         GST_AUTOPLUG_SELECT_TRY,
121         GST_AUTOPLUG_SELECT_EXPOSE,
122         GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
124
125 /*---------------------------------------------------------------------------
126 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
127 ---------------------------------------------------------------------------*/
128
129 /*---------------------------------------------------------------------------
130 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
133
134 /*---------------------------------------------------------------------------
135 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
136 ---------------------------------------------------------------------------*/
137 static int              __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int              __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int              __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int              __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int              __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int              __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void             __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
147
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void             __mmplayer_release_misc(mmplayer_t *player);
150 static void             __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
156
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int              __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int              __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void             __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
161 static void             __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void             __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int              __mmplayer_gst_realize(mmplayer_t *player);
168 static int              __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int              __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int              __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
171
172 /* util */
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void             __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void             __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void             __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
187
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
191
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
196
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 /*===========================================================================================
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                 goto ERROR;
3776         }
3777
3778         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3779         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3780         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3781
3782         /* linking elements in the bucket by added order. */
3783         LOGD("Linking elements in the bucket by added order.");
3784         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3785                 LOGE("failed to link elements");
3786                 goto ERROR;
3787         }
3788
3789         /* done. free allocated variables */
3790         g_list_free(element_bucket);
3791
3792         if (textbin[MMPLAYER_T_QUEUE].gst) {
3793                 GstPad *pad = NULL;
3794                 GstPad *ghostpad = NULL;
3795
3796                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3797                 if (!pad) {
3798                         LOGE("failed to get sink pad of text queue");
3799                         goto ERROR;
3800                 }
3801
3802                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3803                 gst_object_unref(pad);
3804
3805                 if (!ghostpad) {
3806                         LOGE("failed to create ghostpad of textbin");
3807                         goto ERROR;
3808                 }
3809
3810                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3811                         LOGE("failed to add ghostpad to textbin");
3812                         gst_object_unref(ghostpad);
3813                         goto ERROR;
3814                 }
3815         }
3816
3817         return MM_ERROR_NONE;
3818
3819 ERROR:
3820         g_list_free(element_bucket);
3821
3822         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3823                 LOGE("remove textbin sink from sink list");
3824                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3825         }
3826
3827         /* release element at __mmplayer_gst_create_text_sink_bin */
3828         return MM_ERROR_PLAYER_INTERNAL;
3829 }
3830
3831 static int
3832 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3833 {
3834         mmplayer_gst_element_t *textbin = NULL;
3835         GList *element_bucket = NULL;
3836         int surface_type = 0;
3837         gint i = 0;
3838
3839         MMPLAYER_FENTER();
3840
3841         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3842
3843         /* alloc handles */
3844         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3845         if (!textbin) {
3846                 LOGE("failed to allocate memory for textbin");
3847                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3848         }
3849
3850         /* create bin */
3851         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3852         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3853         if (!textbin[MMPLAYER_T_BIN].gst) {
3854                 LOGE("failed to create textbin");
3855                 goto ERROR;
3856         }
3857
3858         /* take it */
3859         player->pipeline->textbin = textbin;
3860
3861         /* fakesink */
3862         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3863         LOGD("surface type for subtitle : %d", surface_type);
3864         switch (surface_type) {
3865         case MM_DISPLAY_SURFACE_OVERLAY:
3866         case MM_DISPLAY_SURFACE_NULL:
3867         case MM_DISPLAY_SURFACE_REMOTE:
3868                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3869                         LOGE("failed to make plain text elements");
3870                         goto ERROR;
3871                 }
3872                 break;
3873         default:
3874                 goto ERROR;
3875                 break;
3876         }
3877
3878         MMPLAYER_FLEAVE();
3879
3880         return MM_ERROR_NONE;
3881
3882 ERROR:
3883
3884         LOGD("ERROR : releasing textbin");
3885
3886         g_list_free(element_bucket);
3887
3888         /* release signal */
3889         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3890
3891         /* release element which are not added to bin */
3892         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3893                 /* NOTE : skip bin */
3894                 if (textbin[i].gst) {
3895                         GstObject *parent = NULL;
3896                         parent = gst_element_get_parent(textbin[i].gst);
3897
3898                         if (!parent) {
3899                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3900                                 textbin[i].gst = NULL;
3901                         } else {
3902                                 gst_object_unref(GST_OBJECT(parent));
3903                         }
3904                 }
3905         }
3906
3907         /* release textbin with it's children */
3908         if (textbin[MMPLAYER_T_BIN].gst)
3909                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3910
3911         MMPLAYER_FREEIF(textbin);
3912         player->pipeline->textbin = NULL;
3913
3914         MMPLAYER_FLEAVE();
3915         return MM_ERROR_PLAYER_INTERNAL;
3916 }
3917
3918 static int
3919 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3920 {
3921         mmplayer_gst_element_t *mainbin = NULL;
3922         mmplayer_gst_element_t *textbin = NULL;
3923         MMHandleType attrs = 0;
3924         GstElement *subsrc = NULL;
3925         GstElement *subparse = NULL;
3926         gchar *subtitle_uri = NULL;
3927         const gchar *charset = NULL;
3928         GstPad *pad = NULL;
3929
3930         MMPLAYER_FENTER();
3931
3932         /* get mainbin */
3933         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3934                                                                 player->pipeline &&
3935                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3936
3937         mainbin = player->pipeline->mainbin;
3938
3939         attrs = MMPLAYER_GET_ATTRS(player);
3940         if (!attrs) {
3941                 LOGE("cannot get content attribute");
3942                 return MM_ERROR_PLAYER_INTERNAL;
3943         }
3944
3945         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3946         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3947                 LOGE("subtitle uri is not proper filepath.");
3948                 return MM_ERROR_PLAYER_INVALID_URI;
3949         }
3950
3951         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3952                 LOGE("failed to get storage info of subtitle path");
3953                 return MM_ERROR_PLAYER_INVALID_URI;
3954         }
3955
3956         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3957
3958         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3959         player->subtitle_language_list = NULL;
3960         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3961
3962         /* create the subtitle source */
3963         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3964         if (!subsrc) {
3965                 LOGE("failed to create filesrc element");
3966                 goto ERROR;
3967         }
3968         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3969
3970         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3971         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3972
3973         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3974                 LOGW("failed to add queue");
3975                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3976                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3977                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3978                 goto ERROR;
3979         }
3980
3981         /* subparse */
3982         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3983         if (!subparse) {
3984                 LOGE("failed to create subparse element");
3985                 goto ERROR;
3986         }
3987
3988         charset = _mmplayer_get_charset(subtitle_uri);
3989         if (charset) {
3990                 LOGD("detected charset is %s", charset);
3991                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3992         }
3993
3994         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3995         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3996
3997         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3998                 LOGW("failed to add subparse");
3999                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4000                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4001                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4002                 goto ERROR;
4003         }
4004
4005         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4006                 LOGW("failed to link subsrc and subparse");
4007                 goto ERROR;
4008         }
4009
4010         player->play_subtitle = TRUE;
4011         player->adjust_subtitle_pos = 0;
4012
4013         LOGD("play subtitle using subtitle file");
4014
4015         if (player->pipeline->textbin == NULL) {
4016                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4017                         LOGE("failed to create text sink bin. continuing without text");
4018                         goto ERROR;
4019                 }
4020
4021                 textbin = player->pipeline->textbin;
4022
4023                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4024                         LOGW("failed to add textbin");
4025
4026                         /* release signal */
4027                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4028
4029                         /* release textbin with it's children */
4030                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4031                         MMPLAYER_FREEIF(player->pipeline->textbin);
4032                         player->pipeline->textbin = textbin = NULL;
4033                         goto ERROR;
4034                 }
4035
4036                 LOGD("link text input selector and textbin ghost pad");
4037
4038                 player->textsink_linked = 1;
4039                 player->external_text_idx = 0;
4040                 LOGI("textsink is linked");
4041         } else {
4042                 textbin = player->pipeline->textbin;
4043                 LOGD("text bin has been created. reuse it.");
4044                 player->external_text_idx = 1;
4045         }
4046
4047         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4048                 LOGW("failed to link subparse and textbin");
4049                 goto ERROR;
4050         }
4051
4052         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4053         if (!pad) {
4054                 LOGE("failed to get sink pad from textsink to probe data");
4055                 goto ERROR;
4056         }
4057
4058         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4059                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4060
4061         gst_object_unref(pad);
4062         pad = NULL;
4063
4064         /* create dot. for debugging */
4065         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4066         MMPLAYER_FLEAVE();
4067
4068         return MM_ERROR_NONE;
4069
4070 ERROR:
4071         /* release text pipeline resource */
4072         player->textsink_linked = 0;
4073
4074         /* release signal */
4075         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4076
4077         if (player->pipeline->textbin) {
4078                 LOGE("remove textbin");
4079
4080                 /* release textbin with it's children */
4081                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4082                 MMPLAYER_FREEIF(player->pipeline->textbin);
4083                 player->pipeline->textbin = NULL;
4084
4085         }
4086
4087         /* release subtitle elem */
4088         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4089         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4090
4091         return MM_ERROR_PLAYER_INTERNAL;
4092 }
4093
4094 gboolean
4095 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4096 {
4097         mmplayer_t *player = (mmplayer_t *)data;
4098         MMMessageParamType msg = {0, };
4099         GstClockTime duration = 0;
4100         gpointer text = NULL;
4101         guint text_size = 0;
4102         gboolean ret = TRUE;
4103         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4104
4105         MMPLAYER_FENTER();
4106
4107         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4108         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4109
4110         if (player->is_subtitle_force_drop) {
4111                 LOGW("subtitle is dropped forcedly.");
4112                 return ret;
4113         }
4114
4115         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4116         text = mapinfo.data;
4117         text_size = mapinfo.size;
4118
4119         if (player->set_mode.subtitle_off) {
4120                 LOGD("subtitle is OFF.");
4121                 return TRUE;
4122         }
4123
4124         if (!text || (text_size == 0)) {
4125                 LOGD("There is no subtitle to be displayed.");
4126                 return TRUE;
4127         }
4128
4129         msg.data = (void *)text;
4130
4131         duration = GST_BUFFER_DURATION(buffer);
4132
4133         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4134                 if (player->duration > GST_BUFFER_PTS(buffer))
4135                         duration = player->duration - GST_BUFFER_PTS(buffer);
4136                 else
4137                         duration = 0;
4138                 LOGI("subtitle duration is invalid, subtitle duration change "
4139                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4140         }
4141         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4142
4143         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4144
4145         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4146         gst_buffer_unmap(buffer, &mapinfo);
4147
4148         MMPLAYER_FLEAVE();
4149
4150         return ret;
4151 }
4152
4153 static GstPadProbeReturn
4154 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4155 {
4156         mmplayer_t *player = (mmplayer_t *)u_data;
4157         GstClockTime cur_timestamp = 0;
4158         gint64 adjusted_timestamp = 0;
4159         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4160
4161         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4162
4163         if (player->set_mode.subtitle_off) {
4164                 LOGD("subtitle is OFF.");
4165                 return TRUE;
4166         }
4167
4168         if (player->adjust_subtitle_pos == 0) {
4169                 LOGD("nothing to do");
4170                 return TRUE;
4171         }
4172
4173         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4174         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4175
4176         if (adjusted_timestamp < 0) {
4177                 LOGD("adjusted_timestamp under zero");
4178                 MMPLAYER_FLEAVE();
4179                 return FALSE;
4180         }
4181
4182         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4183         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4184                                 GST_TIME_ARGS(cur_timestamp),
4185                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4186
4187         return GST_PAD_PROBE_OK;
4188 }
4189
4190 static int
4191 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4192 {
4193         MMPLAYER_FENTER();
4194
4195         /* check player and subtitlebin are created */
4196         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4197         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4198
4199         if (position == 0) {
4200                 LOGD("nothing to do");
4201                 MMPLAYER_FLEAVE();
4202                 return MM_ERROR_NONE;
4203         }
4204
4205         /* check current position */
4206         player->adjust_subtitle_pos = position;
4207
4208         LOGD("save adjust_subtitle_pos in player");
4209
4210         MMPLAYER_FLEAVE();
4211
4212         return MM_ERROR_NONE;
4213 }
4214
4215 /**
4216  * This function is to create  audio or video pipeline for playing.
4217  *
4218  * @param       player          [in]    handle of player
4219  *
4220  * @return      This function returns zero on success.
4221  * @remark
4222  * @see
4223  */
4224 static int
4225 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4226 {
4227         int ret = MM_ERROR_NONE;
4228         mmplayer_gst_element_t *mainbin = NULL;
4229         MMHandleType attrs = 0;
4230
4231         MMPLAYER_FENTER();
4232         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4233
4234         /* get profile attribute */
4235         attrs = MMPLAYER_GET_ATTRS(player);
4236         if (!attrs) {
4237                 LOGE("failed to get content attribute");
4238                 goto INIT_ERROR;
4239         }
4240
4241         /* create pipeline handles */
4242         if (player->pipeline) {
4243                 LOGE("pipeline should be released before create new one");
4244                 goto INIT_ERROR;
4245         }
4246
4247         player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4248
4249         /* create mainbin */
4250         mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4251         if (mainbin == NULL)
4252                 goto INIT_ERROR;
4253
4254         /* create pipeline */
4255         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4256         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4257         if (!mainbin[MMPLAYER_M_PIPE].gst) {
4258                 LOGE("failed to create pipeline");
4259                 g_free(mainbin);
4260                 goto INIT_ERROR;
4261         }
4262
4263         player->pipeline->mainbin = mainbin;
4264
4265         /* create the source and decoder elements */
4266         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4267                 ret = _mmplayer_gst_build_es_pipeline(player);
4268         } else {
4269                 if (MMPLAYER_USE_DECODEBIN(player))
4270                         ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4271                 else
4272                         ret = _mmplayer_gst_build_pipeline_with_src(player);
4273         }
4274
4275         if (ret != MM_ERROR_NONE) {
4276                 LOGE("failed to create some elements");
4277                 goto INIT_ERROR;
4278         }
4279
4280         /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4281         if (__mmplayer_check_subtitle(player)
4282                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4283                 LOGE("failed to create text pipeline");
4284
4285         /* add bus watch */
4286         ret = _mmplayer_gst_add_bus_watch(player);
4287         if (ret != MM_ERROR_NONE) {
4288                 LOGE("failed to add bus watch");
4289                 goto INIT_ERROR;
4290         }
4291
4292         MMPLAYER_FLEAVE();
4293         return MM_ERROR_NONE;
4294
4295 INIT_ERROR:
4296         _mmplayer_bus_watcher_remove(player);
4297         __mmplayer_gst_destroy_pipeline(player);
4298         return MM_ERROR_PLAYER_INTERNAL;
4299 }
4300
4301 static void
4302 __mmplayer_reset_gapless_state(mmplayer_t *player)
4303 {
4304         MMPLAYER_FENTER();
4305         MMPLAYER_RETURN_IF_FAIL(player
4306                 && player->pipeline
4307                 && player->pipeline->audiobin
4308                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4309
4310         memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4311
4312         MMPLAYER_FLEAVE();
4313         return;
4314 }
4315
4316 static int
4317 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4318 {
4319         gint timeout = 0;
4320         int ret = MM_ERROR_NONE;
4321
4322         MMPLAYER_FENTER();
4323
4324         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4325
4326         /* cleanup stuffs */
4327         MMPLAYER_FREEIF(player->type);
4328         player->no_more_pad = FALSE;
4329         player->num_dynamic_pad = 0;
4330
4331         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4332         player->subtitle_language_list = NULL;
4333         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4334
4335         MMPLAYER_RECONFIGURE_LOCK(player);
4336         __mmplayer_reset_gapless_state(player);
4337         MMPLAYER_RECONFIGURE_UNLOCK(player);
4338
4339         if (player->streamer) {
4340                 _mm_player_streaming_initialize(player->streamer, FALSE);
4341                 _mm_player_streaming_destroy(player->streamer);
4342                 player->streamer = NULL;
4343         }
4344
4345         /* cleanup unlinked mime type */
4346         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4347         MMPLAYER_FREEIF(player->unlinked_video_mime);
4348         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4349
4350         /* cleanup running stuffs */
4351         _mmplayer_cancel_eos_timer(player);
4352
4353         /* cleanup gst stuffs */
4354         if (player->pipeline) {
4355                 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4356                 GstTagList *tag_list = player->pipeline->tag_list;
4357
4358                 /* first we need to disconnect all signal hander */
4359                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4360
4361                 if (mainbin) {
4362                         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4363                         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4364                         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4365                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4366                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4367                         gst_object_unref(bus);
4368
4369                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4370                         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4371                         if (ret != MM_ERROR_NONE) {
4372                                 LOGE("fail to change state to NULL");
4373                                 return MM_ERROR_PLAYER_INTERNAL;
4374                         }
4375
4376                         LOGW("succeeded in changing state to NULL");
4377
4378                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4379
4380                         /* free fakesink */
4381                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4382                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4383
4384                         MMPLAYER_FREEIF(audiobin);
4385                         MMPLAYER_FREEIF(videobin);
4386                         MMPLAYER_FREEIF(textbin);
4387                         MMPLAYER_FREEIF(mainbin);
4388                 }
4389
4390                 if (tag_list)
4391                         gst_tag_list_unref(tag_list);
4392
4393                 MMPLAYER_FREEIF(player->pipeline);
4394         }
4395         MMPLAYER_FREEIF(player->album_art);
4396
4397         if (player->type_caps) {
4398                 gst_caps_unref(player->type_caps);
4399                 player->type_caps = NULL;
4400         }
4401
4402         if (player->v_stream_caps) {
4403                 gst_caps_unref(player->v_stream_caps);
4404                 player->v_stream_caps = NULL;
4405         }
4406
4407         if (player->a_stream_caps) {
4408                 gst_caps_unref(player->a_stream_caps);
4409                 player->a_stream_caps = NULL;
4410         }
4411
4412         if (player->s_stream_caps) {
4413                 gst_caps_unref(player->s_stream_caps);
4414                 player->s_stream_caps = NULL;
4415         }
4416         _mmplayer_track_destroy(player);
4417
4418         if (player->sink_elements)
4419                 g_list_free(player->sink_elements);
4420         player->sink_elements = NULL;
4421
4422         if (player->bufmgr) {
4423                 tbm_bufmgr_deinit(player->bufmgr);
4424                 player->bufmgr = NULL;
4425         }
4426
4427         LOGW("finished destroy pipeline");
4428
4429         MMPLAYER_FLEAVE();
4430
4431         return ret;
4432 }
4433
4434 static int
4435 __mmplayer_gst_realize(mmplayer_t *player)
4436 {
4437         gint timeout = 0;
4438         int ret = MM_ERROR_NONE;
4439
4440         MMPLAYER_FENTER();
4441
4442         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4443
4444         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4445
4446         ret = __mmplayer_gst_create_pipeline(player);
4447         if (ret) {
4448                 LOGE("failed to create pipeline");
4449                 return ret;
4450         }
4451
4452         /* set pipeline state to READY */
4453         /* NOTE : state change to READY must be performed sync. */
4454         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4455         ret = _mmplayer_gst_set_state(player,
4456                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4457
4458         if (ret != MM_ERROR_NONE) {
4459                 /* return error if failed to set state */
4460                 LOGE("failed to set READY state");
4461                 return ret;
4462         }
4463
4464         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4465
4466         /* create dot before error-return. for debugging */
4467         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4468
4469         MMPLAYER_FLEAVE();
4470
4471         return ret;
4472 }
4473
4474 static int
4475 __mmplayer_gst_unrealize(mmplayer_t *player)
4476 {
4477         int ret = MM_ERROR_NONE;
4478
4479         MMPLAYER_FENTER();
4480
4481         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4482
4483         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4484         MMPLAYER_PRINT_STATE(player);
4485
4486         /* release miscellaneous information */
4487         __mmplayer_release_misc(player);
4488
4489         /* destroy pipeline */
4490         ret = __mmplayer_gst_destroy_pipeline(player);
4491         if (ret != MM_ERROR_NONE) {
4492                 LOGE("failed to destroy pipeline");
4493                 return ret;
4494         }
4495
4496         /* release miscellaneous information.
4497            these info needs to be released after pipeline is destroyed. */
4498         __mmplayer_release_misc_post(player);
4499
4500         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4501
4502         MMPLAYER_FLEAVE();
4503
4504         return ret;
4505 }
4506
4507 static int
4508 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4509 {
4510         MMPLAYER_FENTER();
4511
4512         if (!player) {
4513                 LOGW("set_message_callback is called with invalid player handle");
4514                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4515         }
4516
4517         player->msg_cb = callback;
4518         player->msg_cb_param = user_param;
4519
4520         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4521
4522         MMPLAYER_FLEAVE();
4523
4524         return MM_ERROR_NONE;
4525 }
4526
4527 int
4528 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4529 {
4530         int ret = MM_ERROR_NONE;
4531         char *path = NULL;
4532
4533         MMPLAYER_FENTER();
4534
4535         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4536         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4537         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4538
4539         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4540
4541         if (strstr(uri, "es_buff://")) {
4542                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4543         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4544                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4545         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4546                 gchar *tmp = NULL;
4547                 tmp = g_ascii_strdown(uri, strlen(uri));
4548                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4549                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4550                 else
4551                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4552                 g_free(tmp);
4553         } else if (strstr(uri, "mms://")) {
4554                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4555         } else if ((path = strstr(uri, "mem://"))) {
4556                 ret = __mmplayer_set_mem_uri(data, path, param);
4557         } else {
4558                 ret = __mmplayer_set_file_uri(data, uri);
4559         }
4560
4561         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4562                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4563         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4564                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4565
4566         /* dump parse result */
4567         SECURE_LOGW("incoming uri : %s", uri);
4568         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4569                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4570
4571         MMPLAYER_FLEAVE();
4572
4573         return ret;
4574 }
4575
4576 static int
4577 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4578                 void *user_data)
4579 {
4580         mmplayer_t *player = NULL;
4581         MMMessageParamType msg = {0, };
4582         gint64 pos = 0;
4583         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4584
4585         MMPLAYER_FENTER();
4586
4587         if (!user_data) {
4588                 LOGE("user_data is null");
4589                 return TRUE;
4590         }
4591
4592         player = (mmplayer_t *)user_data;
4593
4594         if (!player->pipeline || !player->attrs) {
4595                 LOGW("not initialized");
4596                 return TRUE;
4597         }
4598
4599         LOGD("cmd lock player, cmd state : %d", player->cmd);
4600         MMPLAYER_CMD_LOCK(player);
4601         LOGD("cmd locked player");
4602
4603         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4604                 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4605                 LOGW("player already destroyed");
4606                 MMPLAYER_CMD_UNLOCK(player);
4607                 return TRUE;
4608         }
4609
4610         player->interrupted_by_resource = TRUE;
4611
4612         /* get last play position */
4613         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4614                 msg.union_type = MM_MSG_UNION_TIME;
4615                 msg.time.elapsed = pos;
4616                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4617         } else {
4618                 LOGW("failed to get play position.");
4619         }
4620
4621         LOGD("video resource conflict so, resource will be freed by unrealizing");
4622         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4623                 LOGE("failed to unrealize");
4624
4625         MMPLAYER_CMD_UNLOCK(player);
4626
4627         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4628                 player->hw_resource[res_idx] = NULL;
4629         }
4630
4631         MMPLAYER_FLEAVE();
4632         return TRUE; /* release all the resources */
4633 }
4634
4635 static void
4636 __mmplayer_initialize_video_roi(mmplayer_t *player)
4637 {
4638         player->video_roi.scale_x = 0.0;
4639         player->video_roi.scale_y = 0.0;
4640         player->video_roi.scale_width = 1.0;
4641         player->video_roi.scale_height = 1.0;
4642 }
4643
4644 int
4645 _mmplayer_create_player(MMHandleType handle)
4646 {
4647         int ret = MM_ERROR_PLAYER_INTERNAL;
4648         bool enabled = false;
4649
4650         mmplayer_t *player = MM_PLAYER_CAST(handle);
4651
4652         MMPLAYER_FENTER();
4653
4654         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4655
4656         /* initialize player state */
4657         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4658         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4659         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4660         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4661
4662         /* check current state */
4663         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4664
4665         /* construct attributes */
4666         player->attrs = _mmplayer_construct_attribute(handle);
4667
4668         if (!player->attrs) {
4669                 LOGE("Failed to construct attributes");
4670                 return ret;
4671         }
4672
4673         /* initialize gstreamer with configured parameter */
4674         if (!__mmplayer_init_gstreamer(player)) {
4675                 LOGE("Initializing gstreamer failed");
4676                 _mmplayer_deconstruct_attribute(handle);
4677                 return ret;
4678         }
4679
4680         /* create lock. note that g_tread_init() has already called in gst_init() */
4681         g_mutex_init(&player->fsink_lock);
4682
4683         /* create update tag lock */
4684         g_mutex_init(&player->update_tag_lock);
4685
4686         /* create gapless play mutex */
4687         g_mutex_init(&player->gapless_play_thread_mutex);
4688
4689         /* create gapless play cond */
4690         g_cond_init(&player->gapless_play_thread_cond);
4691
4692         /* create gapless play thread */
4693         player->gapless_play_thread =
4694                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4695         if (!player->gapless_play_thread) {
4696                 LOGE("failed to create gapless play thread");
4697                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4698                 g_mutex_clear(&player->gapless_play_thread_mutex);
4699                 g_cond_clear(&player->gapless_play_thread_cond);
4700                 goto ERROR;
4701         }
4702
4703         player->bus_msg_q = g_queue_new();
4704         if (!player->bus_msg_q) {
4705                 LOGE("failed to create queue for bus_msg");
4706                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4707                 goto ERROR;
4708         }
4709
4710         ret = _mmplayer_initialize_video_capture(player);
4711         if (ret != MM_ERROR_NONE) {
4712                 LOGE("failed to initialize video capture");
4713                 goto ERROR;
4714         }
4715
4716         /* initialize resource manager */
4717         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4718                 __resource_release_cb, player, &player->resource_manager)
4719                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4720                 LOGE("failed to create resource manager");
4721                 ret = MM_ERROR_PLAYER_INTERNAL;
4722                 goto ERROR;
4723         }
4724
4725         /* create video bo lock and cond */
4726         g_mutex_init(&player->video_bo_mutex);
4727         g_cond_init(&player->video_bo_cond);
4728
4729         /* create subtitle info lock and cond */
4730         g_mutex_init(&player->subtitle_info_mutex);
4731         g_cond_init(&player->subtitle_info_cond);
4732
4733         player->streaming_type = STREAMING_SERVICE_NONE;
4734
4735         /* give default value of audio effect setting */
4736         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4737         player->sound.rg_enable = false;
4738         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4739
4740         player->play_subtitle = FALSE;
4741         player->has_closed_caption = FALSE;
4742         player->pending_resume = FALSE;
4743         if (player->ini.dump_element_keyword[0][0] == '\0')
4744                 player->ini.set_dump_element_flag = FALSE;
4745         else
4746                 player->ini.set_dump_element_flag = TRUE;
4747
4748         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4749         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4750         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4751
4752         /* Set video360 settings to their defaults for just-created player.
4753          * */
4754
4755         player->is_360_feature_enabled = FALSE;
4756         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4757                 LOGI("spherical feature info: %d", enabled);
4758                 if (enabled)
4759                         player->is_360_feature_enabled = TRUE;
4760         } else {
4761                 LOGE("failed to get spherical feature info");
4762         }
4763
4764         player->is_content_spherical = FALSE;
4765         player->is_video360_enabled = TRUE;
4766         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4767         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4768         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4769         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4770         player->video360_zoom = 1.0f;
4771         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4772         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4773
4774         __mmplayer_initialize_video_roi(player);
4775
4776         /* set player state to null */
4777         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4778         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4779
4780         MMPLAYER_FLEAVE();
4781
4782         return MM_ERROR_NONE;
4783
4784 ERROR:
4785         /* free lock */
4786         g_mutex_clear(&player->fsink_lock);
4787         /* free update tag lock */
4788         g_mutex_clear(&player->update_tag_lock);
4789         g_queue_free(player->bus_msg_q);
4790         player->bus_msg_q = NULL;
4791         /* free gapless play thread */
4792         if (player->gapless_play_thread) {
4793                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4794                 player->gapless_play_thread_exit = TRUE;
4795                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4796                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4797
4798                 g_thread_join(player->gapless_play_thread);
4799                 player->gapless_play_thread = NULL;
4800
4801                 g_mutex_clear(&player->gapless_play_thread_mutex);
4802                 g_cond_clear(&player->gapless_play_thread_cond);
4803         }
4804
4805         /* release attributes */
4806         _mmplayer_deconstruct_attribute(handle);
4807
4808         MMPLAYER_FLEAVE();
4809
4810         return ret;
4811 }
4812
4813 static gboolean
4814 __mmplayer_init_gstreamer(mmplayer_t *player)
4815 {
4816         static gboolean initialized = FALSE;
4817         static const int max_argc = 50;
4818         gint *argc = NULL;
4819         gchar **argv = NULL;
4820         gchar **argv2 = NULL;
4821         GError *err = NULL;
4822         int i = 0;
4823         int arg_count = 0;
4824
4825         if (initialized) {
4826                 LOGD("gstreamer already initialized.");
4827                 return TRUE;
4828         }
4829
4830         /* alloc */
4831         argc = malloc(sizeof(int));
4832         argv = malloc(sizeof(gchar *) * max_argc);
4833         argv2 = malloc(sizeof(gchar *) * max_argc);
4834
4835         if (!argc || !argv || !argv2)
4836                 goto ERROR;
4837
4838         memset(argv, 0, sizeof(gchar *) * max_argc);
4839         memset(argv2, 0, sizeof(gchar *) * max_argc);
4840
4841         /* add initial */
4842         *argc = 1;
4843         argv[0] = g_strdup("mmplayer");
4844
4845         /* add gst_param */
4846         for (i = 0; i < 5; i++) {
4847                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4848                 if (strlen(player->ini.gst_param[i]) > 0) {
4849                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4850                         (*argc)++;
4851                 }
4852         }
4853
4854         /* we would not do fork for scanning plugins */
4855         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4856         (*argc)++;
4857
4858         /* check disable registry scan */
4859         if (player->ini.skip_rescan) {
4860                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4861                 (*argc)++;
4862         }
4863
4864         /* check disable segtrap */
4865         if (player->ini.disable_segtrap) {
4866                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4867                 (*argc)++;
4868         }
4869
4870         LOGD("initializing gstreamer with following parameter");
4871         LOGD("argc : %d", *argc);
4872         arg_count = *argc;
4873
4874         for (i = 0; i < arg_count; i++) {
4875                 argv2[i] = argv[i];
4876                 LOGD("argv[%d] : %s", i, argv2[i]);
4877         }
4878
4879         /* initializing gstreamer */
4880         if (!gst_init_check(argc, &argv, &err)) {
4881                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4882                 if (err)
4883                         g_error_free(err);
4884
4885                 goto ERROR;
4886         }
4887         /* release */
4888         for (i = 0; i < arg_count; i++) {
4889 #ifdef __DEBUG__
4890                 LOGD("release - argv[%d] : %s", i, argv2[i]);
4891 #endif
4892                 MMPLAYER_FREEIF(argv2[i]);
4893         }
4894
4895         MMPLAYER_FREEIF(argv);
4896         MMPLAYER_FREEIF(argv2);
4897         MMPLAYER_FREEIF(argc);
4898
4899         /* done */
4900         initialized = TRUE;
4901
4902         return TRUE;
4903
4904 ERROR:
4905
4906         /* release */
4907         for (i = 0; i < arg_count; i++) {
4908                 LOGD("free[%d] : %s", i, argv2[i]);
4909                 MMPLAYER_FREEIF(argv2[i]);
4910         }
4911
4912         MMPLAYER_FREEIF(argv);
4913         MMPLAYER_FREEIF(argv2);
4914         MMPLAYER_FREEIF(argc);
4915
4916         return FALSE;
4917 }
4918
4919 static void
4920 __mmplayer_check_async_state_transition(mmplayer_t *player)
4921 {
4922         GstState element_state = GST_STATE_VOID_PENDING;
4923         GstState element_pending_state = GST_STATE_VOID_PENDING;
4924         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4925         GstElement *element = NULL;
4926         gboolean async = FALSE;
4927
4928         /* check player handle */
4929         MMPLAYER_RETURN_IF_FAIL(player &&
4930                                                 player->pipeline &&
4931                                                 player->pipeline->mainbin &&
4932                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4933
4934         if (player->attrs)
4935                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4936
4937         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4938                 LOGD("don't need to check the pipeline state");
4939                 return;
4940         }
4941
4942         MMPLAYER_PRINT_STATE(player);
4943
4944         /* wait for state transition */
4945         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4946         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4947
4948         if (ret == GST_STATE_CHANGE_FAILURE) {
4949                 LOGE(" [%s] state : %s   pending : %s",
4950                         GST_ELEMENT_NAME(element),
4951                         gst_element_state_get_name(element_state),
4952                         gst_element_state_get_name(element_pending_state));
4953
4954                 /* dump state of all element */
4955                 _mmplayer_dump_pipeline_state(player);
4956
4957                 return;
4958         }
4959
4960         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4961         return;
4962 }
4963
4964 int
4965 _mmplayer_destroy(MMHandleType handle)
4966 {
4967         mmplayer_t *player = MM_PLAYER_CAST(handle);
4968
4969         MMPLAYER_FENTER();
4970
4971         /* check player handle */
4972         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4973
4974         /* destroy can called at anytime */
4975         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4976
4977         /* check async state transition */
4978         __mmplayer_check_async_state_transition(player);
4979
4980         /* release gapless play thread */
4981         if (player->gapless_play_thread) {
4982                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4983                 player->gapless_play_thread_exit = TRUE;
4984                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4985                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4986
4987                 LOGD("waiting for gapless play thread exit");
4988                 g_thread_join(player->gapless_play_thread);
4989                 g_mutex_clear(&player->gapless_play_thread_mutex);
4990                 g_cond_clear(&player->gapless_play_thread_cond);
4991                 LOGD("gapless play thread released");
4992         }
4993
4994         _mmplayer_release_video_capture(player);
4995
4996         /* release miscellaneous information */
4997         __mmplayer_release_misc(player);
4998
4999         /* release pipeline */
5000         if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5001                 LOGE("failed to destroy pipeline");
5002                 return MM_ERROR_PLAYER_INTERNAL;
5003         }
5004
5005         __mmplayer_destroy_hw_resource(player);
5006
5007         g_queue_free(player->bus_msg_q);
5008
5009         /* release subtitle info lock and cond */
5010         g_mutex_clear(&player->subtitle_info_mutex);
5011         g_cond_clear(&player->subtitle_info_cond);
5012
5013         __mmplayer_release_dump_list(player->dump_list);
5014
5015         /* release miscellaneous information.
5016            these info needs to be released after pipeline is destroyed. */
5017         __mmplayer_release_misc_post(player);
5018
5019         /* release attributes */
5020         _mmplayer_deconstruct_attribute(handle);
5021
5022         if (player->uri_info.uri_list) {
5023                 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5024                 player->uri_info.uri_list = NULL;
5025         }
5026
5027         /* release lock */
5028         g_mutex_clear(&player->fsink_lock);
5029
5030         /* release lock */
5031         g_mutex_clear(&player->update_tag_lock);
5032
5033         /* release video bo lock and cond */
5034         g_mutex_clear(&player->video_bo_mutex);
5035         g_cond_clear(&player->video_bo_cond);
5036
5037         MMPLAYER_FLEAVE();
5038
5039         return MM_ERROR_NONE;
5040 }
5041
5042 int
5043 _mmplayer_realize(MMHandleType hplayer)
5044 {
5045         mmplayer_t *player = (mmplayer_t *)hplayer;
5046         int ret = MM_ERROR_NONE;
5047         char *uri = NULL;
5048         void *param = NULL;
5049         MMHandleType attrs = 0;
5050
5051         MMPLAYER_FENTER();
5052
5053         /* check player handle */
5054         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5055
5056         /* check current state */
5057         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5058
5059         attrs = MMPLAYER_GET_ATTRS(player);
5060         if (!attrs) {
5061                 LOGE("fail to get attributes.");
5062                 return MM_ERROR_PLAYER_INTERNAL;
5063         }
5064         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5065         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
5066
5067         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5068                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5069
5070                 if (ret != MM_ERROR_NONE) {
5071                         LOGE("failed to parse profile");
5072                         return ret;
5073                 }
5074         }
5075
5076         if (uri && (strstr(uri, "es_buff://"))) {
5077                 if (strstr(uri, "es_buff://push_mode"))
5078                         player->es_player_push_mode = TRUE;
5079                 else
5080                         player->es_player_push_mode = FALSE;
5081         }
5082
5083         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5084                 LOGW("mms protocol is not supported format.");
5085                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5086         }
5087
5088         if (MMPLAYER_IS_STREAMING(player))
5089                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5090         else
5091                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5092
5093         player->smooth_streaming = FALSE;
5094         player->videodec_linked  = 0;
5095         player->audiodec_linked  = 0;
5096         player->textsink_linked = 0;
5097         player->is_external_subtitle_present = FALSE;
5098         player->is_external_subtitle_added_now = FALSE;
5099         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5100         player->video360_metadata.is_spherical = -1;
5101         player->is_openal_plugin_used = FALSE;
5102         player->subtitle_language_list = NULL;
5103         player->is_subtitle_force_drop = FALSE;
5104
5105         _mmplayer_track_initialize(player);
5106         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5107
5108         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5109                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5110
5111                 player->streamer = _mm_player_streaming_create();
5112                 _mm_player_streaming_initialize(player->streamer, TRUE);
5113
5114                 mm_attrs_multiple_get(player->attrs, NULL,
5115                                 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5116                                 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5117
5118                 if (prebuffer_ms > 0) {
5119                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5120                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5121                 }
5122
5123                 if (rebuffer_ms > 0) {
5124                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5125                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5126                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5127                 }
5128
5129                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5130                                                                 player->streamer->buffering_req.rebuffer_time);
5131         }
5132
5133         /* realize pipeline */
5134         ret = __mmplayer_gst_realize(player);
5135         if (ret != MM_ERROR_NONE)
5136                 LOGE("fail to realize the player.");
5137
5138         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5139
5140         MMPLAYER_FLEAVE();
5141
5142         return ret;
5143 }
5144
5145 int
5146 _mmplayer_unrealize(MMHandleType hplayer)
5147 {
5148         mmplayer_t *player = (mmplayer_t *)hplayer;
5149         int ret = MM_ERROR_NONE;
5150         int rm_ret = MM_ERROR_NONE;
5151         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5152
5153         MMPLAYER_FENTER();
5154
5155         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5156
5157         MMPLAYER_CMD_UNLOCK(player);
5158         _mmplayer_bus_watcher_remove(player);
5159         /* destroy the gst bus msg thread which is created during realize.
5160            this funct have to be called before getting cmd lock. */
5161         _mmplayer_bus_msg_thread_destroy(player);
5162         MMPLAYER_CMD_LOCK(player);
5163
5164         /* check current state */
5165         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5166
5167         /* check async state transition */
5168         __mmplayer_check_async_state_transition(player);
5169
5170         /* unrealize pipeline */
5171         ret = __mmplayer_gst_unrealize(player);
5172
5173         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5174                 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5175                 if (rm_ret != MM_ERROR_NONE)
5176                         LOGE("failed to release [%d] resources", res_idx);
5177         }
5178
5179         player->interrupted_by_resource = FALSE;
5180
5181         MMPLAYER_FLEAVE();
5182         return ret;
5183 }
5184
5185 int
5186 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5187 {
5188         mmplayer_t *player = (mmplayer_t *)hplayer;
5189
5190         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5191
5192         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5193 }
5194
5195 int
5196 _mmplayer_get_state(MMHandleType hplayer, int *state)
5197 {
5198         mmplayer_t *player = (mmplayer_t *)hplayer;
5199
5200         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5201
5202         *state = MMPLAYER_CURRENT_STATE(player);
5203
5204         return MM_ERROR_NONE;
5205 }
5206
5207 static int
5208 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5209 {
5210         GstElement *vol_element = NULL;
5211         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5212
5213         MMPLAYER_FENTER();
5214         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5215         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5216
5217         /* check pipeline handle */
5218         if (!player->pipeline || !player->pipeline->audiobin) {
5219                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5220
5221                 /* NOTE : stored value will be used in create_audiobin
5222                  * returning MM_ERROR_NONE here makes application to able to
5223                  * set audio volume or mute at anytime.
5224                  */
5225                 return MM_ERROR_NONE;
5226         }
5227
5228         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5229                 volume_elem_id = MMPLAYER_A_SINK;
5230
5231         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5232         if (!vol_element) {
5233                 LOGE("failed to get vol element %d", volume_elem_id);
5234                 return MM_ERROR_PLAYER_INTERNAL;
5235         }
5236
5237         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5238
5239         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5240                 LOGE("there is no '%s' property", prop_name);
5241                 return MM_ERROR_PLAYER_INTERNAL;
5242         }
5243
5244         if (!strcmp(prop_name, "volume")) {
5245                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5246         } else if (!strcmp(prop_name, "mute")) {
5247                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5248         } else {
5249                 LOGE("invalid property %s", prop_name);
5250                 return MM_ERROR_PLAYER_INTERNAL;
5251         }
5252
5253         return MM_ERROR_NONE;
5254 }
5255
5256 int
5257 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5258 {
5259         int ret = MM_ERROR_NONE;
5260         mmplayer_t *player = (mmplayer_t *)hplayer;
5261
5262         MMPLAYER_FENTER();
5263         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5264
5265         LOGD("volume = %f", volume);
5266
5267         /* invalid factor range or not */
5268         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5269                 LOGE("Invalid volume value");
5270                 return MM_ERROR_INVALID_ARGUMENT;
5271         }
5272
5273         player->sound.volume = volume;
5274
5275         ret = __mmplayer_gst_set_volume_property(player, "volume");
5276
5277         MMPLAYER_FLEAVE();
5278         return ret;
5279 }
5280
5281 int
5282 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5283 {
5284         mmplayer_t *player = (mmplayer_t *)hplayer;
5285
5286         MMPLAYER_FENTER();
5287
5288         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5289         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5290
5291         *volume = player->sound.volume;
5292
5293         LOGD("current vol = %f", *volume);
5294
5295         MMPLAYER_FLEAVE();
5296         return MM_ERROR_NONE;
5297 }
5298
5299 int
5300 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5301 {
5302         int ret = MM_ERROR_NONE;
5303         mmplayer_t *player = (mmplayer_t *)hplayer;
5304
5305         MMPLAYER_FENTER();
5306         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5307
5308         LOGD("mute = %d", mute);
5309
5310         player->sound.mute = mute;
5311
5312         ret = __mmplayer_gst_set_volume_property(player, "mute");
5313
5314         MMPLAYER_FLEAVE();
5315         return ret;
5316 }
5317
5318 int
5319 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5320 {
5321         mmplayer_t *player = (mmplayer_t *)hplayer;
5322
5323         MMPLAYER_FENTER();
5324
5325         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5326         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5327
5328         *mute = player->sound.mute;
5329
5330         LOGD("current mute = %d", *mute);
5331
5332         MMPLAYER_FLEAVE();
5333
5334         return MM_ERROR_NONE;
5335 }
5336
5337 int
5338 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5339 {
5340         mmplayer_t *player = (mmplayer_t *)hplayer;
5341
5342         MMPLAYER_FENTER();
5343
5344         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5345
5346         player->audio_stream_changed_cb = callback;
5347         player->audio_stream_changed_cb_user_param = user_param;
5348         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5349
5350         MMPLAYER_FLEAVE();
5351
5352         return MM_ERROR_NONE;
5353 }
5354
5355 int
5356 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5357 {
5358         mmplayer_t *player = (mmplayer_t *)hplayer;
5359
5360         MMPLAYER_FENTER();
5361
5362         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5363
5364         player->audio_decoded_cb = callback;
5365         player->audio_decoded_cb_user_param = user_param;
5366         player->audio_extract_opt = opt;
5367         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5368
5369         MMPLAYER_FLEAVE();
5370
5371         return MM_ERROR_NONE;
5372 }
5373
5374 int
5375 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5376 {
5377         mmplayer_t *player = (mmplayer_t *)hplayer;
5378
5379         MMPLAYER_FENTER();
5380
5381         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5382
5383         if (callback && !player->bufmgr)
5384                 player->bufmgr = tbm_bufmgr_init(-1);
5385
5386         player->set_mode.video_export = (callback) ? true : false;
5387         player->video_decoded_cb = callback;
5388         player->video_decoded_cb_user_param = user_param;
5389
5390         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5391
5392         MMPLAYER_FLEAVE();
5393
5394         return MM_ERROR_NONE;
5395 }
5396
5397 int
5398 _mmplayer_start(MMHandleType hplayer)
5399 {
5400         mmplayer_t *player = (mmplayer_t *)hplayer;
5401         gint ret = MM_ERROR_NONE;
5402
5403         MMPLAYER_FENTER();
5404
5405         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5406
5407         /* check current state */
5408         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5409
5410         /* start pipeline */
5411         ret = _mmplayer_gst_start(player);
5412         if (ret != MM_ERROR_NONE)
5413                 LOGE("failed to start player.");
5414
5415         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5416                 LOGD("force playing start even during buffering");
5417                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5418         }
5419
5420         MMPLAYER_FLEAVE();
5421
5422         return ret;
5423 }
5424
5425 /* NOTE: post "not supported codec message" to application
5426  * when one codec is not found during AUTOPLUGGING in MSL.
5427  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5428  * And, if any codec is not found, don't send message here.
5429  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5430  */
5431 int
5432 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5433 {
5434         MMMessageParamType msg_param;
5435         memset(&msg_param, 0, sizeof(MMMessageParamType));
5436         gboolean post_msg_direct = FALSE;
5437
5438         MMPLAYER_FENTER();
5439
5440         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5441
5442         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5443                         player->not_supported_codec, player->can_support_codec);
5444
5445         if (player->not_found_demuxer) {
5446                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5447                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5448
5449                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5450                 MMPLAYER_FREEIF(msg_param.data);
5451
5452                 return MM_ERROR_NONE;
5453         }
5454
5455         if (player->not_supported_codec) {
5456                 if (player->can_support_codec) {
5457                         // There is one codec to play
5458                         post_msg_direct = TRUE;
5459                 } else {
5460                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5461                                 post_msg_direct = TRUE;
5462                 }
5463
5464                 if (post_msg_direct) {
5465                         MMMessageParamType msg_param;
5466                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5467
5468                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5469                                 LOGW("not found AUDIO codec, posting error code to application.");
5470
5471                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5472                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5473                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5474                                 LOGW("not found VIDEO codec, posting error code to application.");
5475
5476                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5477                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5478                         }
5479
5480                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5481
5482                         MMPLAYER_FREEIF(msg_param.data);
5483
5484                         return MM_ERROR_NONE;
5485                 } else {
5486                         // no any supported codec case
5487                         LOGW("not found any codec, posting error code to application.");
5488
5489                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5490                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5491                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5492                         } else {
5493                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5494                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5495                         }
5496
5497                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5498
5499                         MMPLAYER_FREEIF(msg_param.data);
5500                 }
5501         }
5502
5503         MMPLAYER_FLEAVE();
5504
5505         return MM_ERROR_NONE;
5506 }
5507
5508 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5509 {
5510         GstState element_state = GST_STATE_VOID_PENDING;
5511         GstState element_pending_state = GST_STATE_VOID_PENDING;
5512         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5513         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5514
5515         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5516
5517         MMPLAYER_RECONFIGURE_LOCK(player);
5518         if (!player->gapless.reconfigure) {
5519                 MMPLAYER_RECONFIGURE_UNLOCK(player);
5520                 return;
5521         }
5522
5523         LOGI("reconfigure is under process");
5524         MMPLAYER_RECONFIGURE_WAIT(player);
5525         MMPLAYER_RECONFIGURE_UNLOCK(player);
5526         LOGI("reconfigure is completed.");
5527
5528         result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5529                                 &element_state, &element_pending_state, timeout * GST_SECOND);
5530         if (result == GST_STATE_CHANGE_FAILURE)
5531                 LOGW("failed to get pipeline state in %d sec", timeout);
5532
5533         return;
5534 }
5535
5536 /* NOTE : it should be able to call 'stop' anytime*/
5537 int
5538 _mmplayer_stop(MMHandleType hplayer)
5539 {
5540         mmplayer_t *player = (mmplayer_t *)hplayer;
5541         int ret = MM_ERROR_NONE;
5542
5543         MMPLAYER_FENTER();
5544
5545         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5546
5547         /* check current state */
5548         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5549
5550         /* need to wait till the rebuilding pipeline is completed */
5551         __mmplayer_check_pipeline_reconfigure_state(player);
5552         MMPLAYER_RECONFIGURE_LOCK(player);
5553         __mmplayer_reset_gapless_state(player);
5554         MMPLAYER_RECONFIGURE_UNLOCK(player);
5555
5556         /* NOTE : application should not wait for EOS after calling STOP */
5557         _mmplayer_cancel_eos_timer(player);
5558
5559         /* reset */
5560         player->seek_state = MMPLAYER_SEEK_NONE;
5561
5562         /* stop pipeline */
5563         ret = _mmplayer_gst_stop(player);
5564
5565         if (ret != MM_ERROR_NONE)
5566                 LOGE("failed to stop player.");
5567
5568         MMPLAYER_FLEAVE();
5569
5570         return ret;
5571 }
5572
5573 int
5574 _mmplayer_pause(MMHandleType hplayer)
5575 {
5576         mmplayer_t *player = (mmplayer_t *)hplayer;
5577         gint64 pos_nsec = 0;
5578         gboolean async = FALSE;
5579         gint ret = MM_ERROR_NONE;
5580
5581         MMPLAYER_FENTER();
5582
5583         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5584
5585         /* check current state */
5586         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5587
5588         /* check pipeline reconfigure state */
5589         __mmplayer_check_pipeline_reconfigure_state(player);
5590
5591         switch (MMPLAYER_CURRENT_STATE(player)) {
5592         case MM_PLAYER_STATE_READY:
5593                 {
5594                         /* check prepare async or not.
5595                          * In the case of streaming playback, it's recommended to avoid blocking wait.
5596                          */
5597                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5598                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5599
5600                         /* Changing back sync of rtspsrc to async */
5601                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5602                                 LOGD("async prepare working mode for rtsp");
5603                                 async = TRUE;
5604                         }
5605                 }
5606                 break;
5607
5608         case MM_PLAYER_STATE_PLAYING:
5609                 {
5610                         /* NOTE : store current point to overcome some bad operation
5611                         *(returning zero when getting current position in paused state) of some
5612                         * elements
5613                         */
5614                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5615                                 LOGW("getting current position failed in paused");
5616
5617                         player->last_position = pos_nsec;
5618
5619                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5620                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5621                            This causes problem is position calculation during normal pause resume scenarios also.
5622                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5623                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5624                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5625                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5626                         }
5627                 }
5628                 break;
5629         }
5630
5631         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5632                 LOGD("doing async pause in case of ms buff src");
5633                 async = TRUE;
5634         }
5635
5636         /* pause pipeline */
5637         ret = _mmplayer_gst_pause(player, async);
5638         if (ret != MM_ERROR_NONE) {
5639                 LOGE("failed to pause player. ret : 0x%x", ret);
5640                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5641                 return ret;
5642         }
5643
5644         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5645                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5646                         LOGE("failed to update display_rotation");
5647         }
5648
5649         MMPLAYER_FLEAVE();
5650         return MM_ERROR_NONE;
5651 }
5652
5653 /* in case of streaming, pause could take long time.*/
5654 int
5655 _mmplayer_abort_pause(MMHandleType hplayer)
5656 {
5657         mmplayer_t *player = (mmplayer_t *)hplayer;
5658         int ret = MM_ERROR_NONE;
5659
5660         MMPLAYER_FENTER();
5661
5662         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5663                                                 player->pipeline &&
5664                                                 player->pipeline->mainbin,
5665                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5666
5667         LOGD("set the pipeline state to READY");
5668
5669         /* set state to READY */
5670         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5671                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5672         if (ret != MM_ERROR_NONE) {
5673                 LOGE("fail to change state to READY");
5674                 return MM_ERROR_PLAYER_INTERNAL;
5675         }
5676
5677         LOGD("succeeded in changing state to READY");
5678         return ret;
5679 }
5680
5681 int
5682 _mmplayer_resume(MMHandleType hplayer)
5683 {
5684         mmplayer_t *player = (mmplayer_t *)hplayer;
5685         int ret = MM_ERROR_NONE;
5686         gboolean async = FALSE;
5687
5688         MMPLAYER_FENTER();
5689
5690         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5691
5692         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5693                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5694                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5695                         return ret;
5696                 }
5697
5698                 /* Changing back sync mode rtspsrc to async */
5699                 LOGD("async resume for rtsp case");
5700                 async = TRUE;
5701         }
5702
5703         /* check current state */
5704         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5705
5706         ret = _mmplayer_gst_resume(player, async);
5707         if (ret != MM_ERROR_NONE)
5708                 LOGE("failed to resume player.");
5709
5710         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5711                 LOGD("force resume even during buffering");
5712                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5713         }
5714
5715         MMPLAYER_FLEAVE();
5716
5717         return ret;
5718 }
5719
5720 int
5721 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5722 {
5723         mmplayer_t *player = (mmplayer_t *)hplayer;
5724         gint64 pos_nsec = 0;
5725         int ret = MM_ERROR_NONE;
5726         bool mute = false;
5727         signed long long start = 0, stop = 0;
5728         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5729         MMPLAYER_FENTER();
5730
5731         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5732         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5733
5734         /* The sound of video is not supported under 0.0 and over 2.0. */
5735         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5736                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5737                         mute = true;
5738         }
5739         _mmplayer_set_mute(hplayer, mute);
5740
5741         if (player->playback_rate == rate)
5742                 return MM_ERROR_NONE;
5743
5744         /* If the position is reached at start potion during fast backward, EOS is posted.
5745          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5746          */
5747         player->playback_rate = rate;
5748
5749         current_state = MMPLAYER_CURRENT_STATE(player);
5750
5751         if (current_state != MM_PLAYER_STATE_PAUSED)
5752                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5753
5754         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5755
5756         if ((current_state == MM_PLAYER_STATE_PAUSED)
5757                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5758                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5759                 pos_nsec = player->last_position;
5760         }
5761
5762         if (rate >= 0) {
5763                 start = pos_nsec;
5764                 stop = GST_CLOCK_TIME_NONE;
5765         } else {
5766                 start = GST_CLOCK_TIME_NONE;
5767                 stop = pos_nsec;
5768         }
5769
5770         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5771                                 player->playback_rate,
5772                                 GST_FORMAT_TIME,
5773                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5774                                 GST_SEEK_TYPE_SET, start,
5775                                 GST_SEEK_TYPE_SET, stop)) {
5776                 LOGE("failed to set speed playback");
5777                 return MM_ERROR_PLAYER_SEEK;
5778         }
5779
5780         LOGD("succeeded to set speed playback as %0.1f", rate);
5781
5782         MMPLAYER_FLEAVE();
5783
5784         return MM_ERROR_NONE;;
5785 }
5786
5787 int
5788 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5789 {
5790         mmplayer_t *player = (mmplayer_t *)hplayer;
5791         int ret = MM_ERROR_NONE;
5792
5793         MMPLAYER_FENTER();
5794
5795         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5796
5797         /* check pipeline reconfigure state */
5798         __mmplayer_check_pipeline_reconfigure_state(player);
5799
5800         ret = _mmplayer_gst_set_position(player, position, FALSE);
5801
5802         MMPLAYER_FLEAVE();
5803
5804         return ret;
5805 }
5806
5807 int
5808 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5809 {
5810         mmplayer_t *player = (mmplayer_t *)hplayer;
5811         int ret = MM_ERROR_NONE;
5812
5813         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5814         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5815
5816         if (g_strrstr(player->type, "video/mpegts"))
5817                 __mmplayer_update_duration_value(player);
5818
5819         *duration = player->duration;
5820         return ret;
5821 }
5822
5823 int
5824 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5825 {
5826         mmplayer_t *player = (mmplayer_t *)hplayer;
5827         int ret = MM_ERROR_NONE;
5828
5829         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5830
5831         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5832
5833         return ret;
5834 }
5835
5836 int
5837 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5838 {
5839         mmplayer_t *player = (mmplayer_t *)hplayer;
5840         int ret = MM_ERROR_NONE;
5841
5842         MMPLAYER_FENTER();
5843
5844         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5845
5846         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5847
5848         MMPLAYER_FLEAVE();
5849
5850         return ret;
5851 }
5852
5853 static gboolean
5854 __mmplayer_is_midi_type(gchar *str_caps)
5855 {
5856         if ((g_strrstr(str_caps, "audio/midi")) ||
5857                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5858                 (g_strrstr(str_caps, "application/x-smaf")) ||
5859                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5860                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5861                 (g_strrstr(str_caps, "audio/xmf")) ||
5862                 (g_strrstr(str_caps, "audio/mxmf"))) {
5863                 LOGD("midi");
5864                 return TRUE;
5865         }
5866
5867         return FALSE;
5868 }
5869
5870 static gboolean
5871 __mmplayer_is_only_mp3_type(gchar *str_caps)
5872 {
5873         if (g_strrstr(str_caps, "application/x-id3") ||
5874                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5875                 return TRUE;
5876         return FALSE;
5877 }
5878
5879 void
5880 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5881 {
5882         GstStructure *caps_structure = NULL;
5883         gint samplerate = 0;
5884         gint channels = 0;
5885
5886         MMPLAYER_FENTER();
5887         MMPLAYER_RETURN_IF_FAIL(player && caps);
5888
5889         caps_structure = gst_caps_get_structure(caps, 0);
5890
5891         /* set stream information */
5892         gst_structure_get_int(caps_structure, "rate", &samplerate);
5893         gst_structure_get_int(caps_structure, "channels", &channels);
5894
5895         mm_player_set_attribute((MMHandleType)player, NULL,
5896                         "content_audio_samplerate", samplerate,
5897                         "content_audio_channels", channels, NULL);
5898
5899         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5900 }
5901
5902 static void
5903 __mmplayer_update_content_type_info(mmplayer_t *player)
5904 {
5905         MMPLAYER_FENTER();
5906         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5907
5908         if (__mmplayer_is_midi_type(player->type)) {
5909                 player->bypass_audio_effect = TRUE;
5910                 return;
5911         }
5912
5913         if (!player->streamer) {
5914                 LOGD("no need to check streaming type");
5915                 return;
5916         }
5917
5918         if (g_strrstr(player->type, "application/x-hls")) {
5919                 /* If it can't know exact type when it parses uri because of redirection case,
5920                  * it will be fixed by typefinder or when doing autoplugging.
5921                  */
5922                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5923                 player->streamer->is_adaptive_streaming = TRUE;
5924         } else if (g_strrstr(player->type, "application/dash+xml")) {
5925                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5926                 player->streamer->is_adaptive_streaming = TRUE;
5927         }
5928
5929         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5930         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5931                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5932
5933                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5934                         if (player->streamer->is_adaptive_streaming)
5935                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5936                         else
5937                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5938                 }
5939         }
5940
5941         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5942         MMPLAYER_FLEAVE();
5943 }
5944
5945 void
5946 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5947         GstCaps *caps, gpointer data)
5948 {
5949         mmplayer_t *player = (mmplayer_t *)data;
5950
5951         MMPLAYER_FENTER();
5952
5953         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5954
5955         /* store type string */
5956         if (player->type_caps) {
5957                 gst_caps_unref(player->type_caps);
5958                 player->type_caps = NULL;
5959         }
5960
5961         player->type_caps = gst_caps_copy(caps);
5962         MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5963
5964         MMPLAYER_FREEIF(player->type);
5965         player->type = gst_caps_to_string(caps);
5966         if (player->type)
5967                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5968                                 player, player->type, probability, gst_caps_get_size(caps));
5969
5970         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5971                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5972                 LOGE("not support media format");
5973
5974                 if (player->msg_posted == FALSE) {
5975                         MMMessageParamType msg_param;
5976                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5977
5978                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5979                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5980
5981                         /* don't post more if one was sent already */
5982                         player->msg_posted = TRUE;
5983                 }
5984                 return;
5985         }
5986
5987         __mmplayer_update_content_type_info(player);
5988
5989         if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5990                 GstPad *pad = NULL;
5991
5992                 pad = gst_element_get_static_pad(tf, "src");
5993                 if (!pad) {
5994                         LOGE("fail to get typefind src pad.");
5995                         return;
5996                 }
5997
5998                 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5999                         gboolean async = FALSE;
6000                         LOGE("failed to autoplug %s", player->type);
6001
6002                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6003
6004                         if (async && player->msg_posted == FALSE)
6005                                 __mmplayer_handle_missed_plugin(player);
6006                 }
6007                 gst_object_unref(GST_OBJECT(pad));
6008         }
6009         MMPLAYER_FLEAVE();
6010         return;
6011 }
6012
6013 GstElement *
6014 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6015 {
6016         GstElement *decodebin = NULL;
6017
6018         MMPLAYER_FENTER();
6019
6020         /* create decodebin */
6021         decodebin = gst_element_factory_make("decodebin", NULL);
6022
6023         if (!decodebin) {
6024                 LOGE("fail to create decodebin");
6025                 goto ERROR;
6026         }
6027
6028         /* raw pad handling signal */
6029         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6030                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6031
6032         /* no-more-pad pad handling signal */
6033         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6034                                                 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6035
6036         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6037                                                 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6038
6039         /* This signal is emitted when a pad for which there is no further possible
6040            decoding is added to the decodebin.*/
6041         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6042                                                 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6043
6044         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6045            before looking for any elements that can handle that stream.*/
6046         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6047                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6048
6049         if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6050                 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6051                                                         G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6052
6053         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6054            before looking for any elements that can handle that stream.*/
6055         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6056                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6057
6058         /* This signal is emitted once decodebin has finished decoding all the data.*/
6059         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6060                                                 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6061
6062         /* This signal is emitted when a element is added to the bin.*/
6063         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6064                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6065
6066 ERROR:
6067         return decodebin;
6068 }
6069
6070 static GstElement *
6071 __mmplayer_gst_make_queue2(mmplayer_t *player)
6072 {
6073         GstElement *queue2 = NULL;
6074         gint64 dur_bytes = 0L;
6075         mmplayer_gst_element_t *mainbin = NULL;
6076         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6077
6078         MMPLAYER_FENTER();
6079         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6080
6081         mainbin = player->pipeline->mainbin;
6082
6083         queue2 = gst_element_factory_make("queue2", "queue2");
6084         if (!queue2) {
6085                 LOGE("failed to create buffering queue element");
6086                 return NULL;
6087         }
6088
6089         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6090                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6091
6092         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6093
6094         /* NOTE : in case of ts streaming, player could not get the correct duration info *
6095          *                skip the pull mode(file or ring buffering) setting. */
6096         if (dur_bytes > 0) {
6097                 if (!g_strrstr(player->type, "video/mpegts")) {
6098                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6099                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6100                 }
6101         } else {
6102                 dur_bytes = 0;
6103         }
6104
6105         _mm_player_streaming_set_queue2(player->streamer,
6106                                                                         queue2,
6107                                                                         FALSE,
6108                                                                         type,
6109                                                                         (guint64)dur_bytes); /* no meaning at the moment */
6110
6111         return queue2;
6112 }
6113
6114 gboolean
6115 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6116 {
6117         mmplayer_gst_element_t *mainbin = NULL;
6118         GstElement *decodebin = NULL;
6119         GstElement *queue2 = NULL;
6120         GstPad *sinkpad = NULL;
6121         GstPad *qsrcpad = NULL;
6122
6123         MMPLAYER_FENTER();
6124         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6125
6126         mainbin = player->pipeline->mainbin;
6127
6128         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6129
6130                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6131                         LOGW("need to check: muxed buffer is not null");
6132                 }
6133
6134                 queue2 = __mmplayer_gst_make_queue2(player);
6135                 if (!queue2) {
6136                         LOGE("failed to make queue2");
6137                         goto ERROR;
6138                 }
6139
6140                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6141                         LOGE("failed to add buffering queue");
6142                         goto ERROR;
6143                 }
6144
6145                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6146                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6147
6148                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6149                         LOGE("failed to link [%s:%s]-[%s:%s]",
6150                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6151                         goto ERROR;
6152                 }
6153
6154                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6155                         LOGE("failed to sync queue2 state with parent");
6156                         goto ERROR;
6157                 }
6158
6159                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6160                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6161
6162                 srcpad = qsrcpad;
6163
6164                 gst_object_unref(GST_OBJECT(sinkpad));
6165                 sinkpad = NULL;
6166         }
6167
6168         /* create decodebin */
6169         decodebin = _mmplayer_gst_make_decodebin(player);
6170         if (!decodebin) {
6171                 LOGE("failed to make decodebin");
6172                 goto ERROR;
6173         }
6174
6175         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6176                 LOGE("failed to add decodebin");
6177                 goto ERROR;
6178         }
6179
6180         /* to force caps on the decodebin element and avoid reparsing stuff by
6181         * typefind. It also avoids a deadlock in the way typefind activates pads in
6182         * the state change */
6183         g_object_set(decodebin, "sink-caps", caps, NULL);
6184
6185         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6186
6187         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6188                 LOGE("failed to link [%s:%s]-[%s:%s]",
6189                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6190                 goto ERROR;
6191         }
6192
6193         gst_object_unref(GST_OBJECT(sinkpad));
6194         sinkpad = NULL;
6195         gst_object_unref(GST_OBJECT(qsrcpad));
6196         qsrcpad = NULL;
6197
6198         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6199         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6200
6201         /* set decodebin property about buffer in streaming playback. *
6202          * in case of HLS/DASH, it does not need to have big buffer   *
6203          * because it is kind of adaptive streaming.                  */
6204         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6205                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6206                 gint high_percent = 0;
6207
6208                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6209                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6210
6211                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6212
6213                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6214
6215                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6216                                                                                         "high-percent", high_percent,
6217                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6218                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6219                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6220         }
6221
6222         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6223                 LOGE("failed to sync decodebin state with parent");
6224                 goto ERROR;
6225         }
6226
6227         MMPLAYER_FLEAVE();
6228
6229         return TRUE;
6230
6231 ERROR:
6232
6233         if (sinkpad)
6234                 gst_object_unref(GST_OBJECT(sinkpad));
6235
6236         if (qsrcpad)
6237                 gst_object_unref(GST_OBJECT(qsrcpad));
6238
6239         if (queue2) {
6240                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6241                  * You need to explicitly set elements to the NULL state before
6242                  * dropping the final reference, to allow them to clean up.
6243                  */
6244                 gst_element_set_state(queue2, GST_STATE_NULL);
6245
6246                 /* And, it still has a parent "player".
6247                  * You need to let the parent manage the object instead of unreffing the object directly.
6248                  */
6249                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6250                 gst_object_unref(queue2);
6251                 queue2 = NULL;
6252         }
6253
6254         if (decodebin) {
6255                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6256                  * You need to explicitly set elements to the NULL state before
6257                  * dropping the final reference, to allow them to clean up.
6258                  */
6259                 gst_element_set_state(decodebin, GST_STATE_NULL);
6260
6261                 /* And, it still has a parent "player".
6262                  * You need to let the parent manage the object instead of unreffing the object directly.
6263                  */
6264
6265                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6266                 gst_object_unref(decodebin);
6267                 decodebin = NULL;
6268         }
6269
6270         return FALSE;
6271 }
6272
6273 static int
6274 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6275 {
6276         MMPLAYER_FENTER();
6277
6278         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6279         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6280
6281         LOGD("class : %s, mime : %s", factory_class, mime);
6282
6283         /* add missing plugin */
6284         /* NOTE : msl should check missing plugin for image mime type.
6285          * Some motion jpeg clips can have playable audio track.
6286          * So, msl have to play audio after displaying popup written video format not supported.
6287          */
6288         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6289                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6290                         LOGD("not found demuxer");
6291                         player->not_found_demuxer = TRUE;
6292                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6293
6294                         goto DONE;
6295                 }
6296         }
6297
6298         if (!g_strrstr(factory_class, "Demuxer")) {
6299                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6300                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6301                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6302
6303                         /* check that clip have multi tracks or not */
6304                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6305                                 LOGD("video plugin is already linked");
6306                         } else {
6307                                 LOGW("add VIDEO to missing plugin");
6308                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6309                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6310                         }
6311                 } else if (g_str_has_prefix(mime, "audio")) {
6312                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6313                                 LOGD("audio plugin is already linked");
6314                         } else {
6315                                 LOGW("add AUDIO to missing plugin");
6316                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6317                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6318                         }
6319                 }
6320         }
6321
6322 DONE:
6323         MMPLAYER_FLEAVE();
6324
6325         return MM_ERROR_NONE;
6326 }
6327
6328 void
6329 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6330 {
6331         mmplayer_t *player = (mmplayer_t *)data;
6332
6333         MMPLAYER_FENTER();
6334
6335         MMPLAYER_RETURN_IF_FAIL(player);
6336
6337         /* remove fakesink. */
6338         if (!_mmplayer_gst_remove_fakesink(player,
6339                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6340                 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6341                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6342                  * source element are not same. To overcome this situation, this function will called
6343                  * several places and several times. Therefore, this is not an error case.
6344                  */
6345                 return;
6346         }
6347
6348         LOGD("[handle: %p] pipeline has completely constructed", player);
6349
6350         if ((player->msg_posted == FALSE) &&
6351                 (player->cmd >= MMPLAYER_COMMAND_START))
6352                 __mmplayer_handle_missed_plugin(player);
6353
6354         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6355 }
6356
6357 static int
6358 __mmplayer_check_profile(void)
6359 {
6360         char *profileName;
6361         static int profile_tv = -1;
6362
6363         if (__builtin_expect(profile_tv != -1, 1))
6364                 return profile_tv;
6365
6366         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6367         switch (*profileName) {
6368         case 't':
6369         case 'T':
6370                 profile_tv = 1;
6371                 break;
6372         default:
6373                 profile_tv = 0;
6374                 break;
6375         }
6376         free(profileName);
6377
6378         return profile_tv;
6379 }
6380
6381 static gboolean
6382 __mmplayer_get_next_uri(mmplayer_t *player)
6383 {
6384         mmplayer_parse_profile_t profile;
6385         gint uri_idx = 0;
6386         guint num_of_list = 0;
6387         char *uri = NULL;
6388
6389         num_of_list = g_list_length(player->uri_info.uri_list);
6390         uri_idx = player->uri_info.uri_idx;
6391
6392         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6393         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6394                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6395                 if (!uri) {
6396                         LOGW("next uri does not exist");
6397                         continue;
6398                 }
6399
6400                 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6401                         LOGE("failed to parse profile");
6402                         continue;
6403                 }
6404
6405                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6406                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6407                         LOGW("uri type is not supported(%d)", profile.uri_type);
6408                         continue;
6409                 }
6410
6411                 LOGD("success to find next uri %d", uri_idx);
6412                 break;
6413         }
6414
6415         if (!uri || uri_idx == num_of_list) {
6416                 LOGE("failed to find next uri");
6417                 return FALSE;
6418         }
6419
6420         player->uri_info.uri_idx = uri_idx;
6421         if (mm_player_set_attribute((MMHandleType)player, NULL,
6422                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6423                 LOGE("failed to set attribute");
6424                 return FALSE;
6425         }
6426
6427         SECURE_LOGD("next playback uri: %s", uri);
6428         return TRUE;
6429 }
6430
6431 static gboolean
6432 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6433 {
6434 #define REPEAT_COUNT_INFINITE -1
6435 #define REPEAT_COUNT_MIN 2
6436 #define ORIGINAL_URI_ONLY 1
6437
6438         MMHandleType attrs = 0;
6439         gint video = 0;
6440         gint count = 0;
6441         gint gapless = 0;
6442         guint num_of_uri = 0;
6443         int profile_tv = -1;
6444
6445         MMPLAYER_FENTER();
6446
6447         LOGD("checking for gapless play option");
6448
6449         if (player->build_audio_offload) {
6450                 LOGE("offload path is not supportable.");
6451                 goto ERROR;
6452         }
6453
6454         if (player->pipeline->textbin) {
6455                 LOGE("subtitle path is enabled. gapless play is not supported.");
6456                 goto ERROR;
6457         }
6458
6459         attrs = MMPLAYER_GET_ATTRS(player);
6460         if (!attrs) {
6461                 LOGE("fail to get attributes.");
6462                 goto ERROR;
6463         }
6464
6465         mm_attrs_multiple_get(player->attrs, NULL,
6466                         "content_video_found", &video,
6467                         "profile_play_count", &count,
6468                         MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6469
6470         /* gapless playback is not supported in case of video at TV profile. */
6471         profile_tv = __mmplayer_check_profile();
6472         if (profile_tv && video) {
6473                 LOGW("not support video gapless playback");
6474                 goto ERROR;
6475         }
6476
6477         /* check repeat count in case of audio */
6478         if (!gapless &&
6479                 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6480                 LOGW("gapless is disabled");
6481                 goto ERROR;
6482         }
6483
6484         num_of_uri = g_list_length(player->uri_info.uri_list);
6485
6486         LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6487
6488         if (num_of_uri == ORIGINAL_URI_ONLY) {
6489                 /* audio looping path */
6490                 if (count >= REPEAT_COUNT_MIN) {
6491                         /* decrease play count */
6492                         /* we succeeded to rewind. update play count and then wait for next EOS */
6493                         count--;
6494                         mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6495                 } else if (count != REPEAT_COUNT_INFINITE) {
6496                         LOGD("there is no next uri and no repeat");
6497                         goto ERROR;
6498                 }
6499                 LOGD("looping cnt %d", count);
6500         } else {
6501                 /* gapless playback path */
6502                 if (!__mmplayer_get_next_uri(player)) {
6503                         LOGE("failed to get next uri");
6504                         goto ERROR;
6505                 }
6506         }
6507         return TRUE;
6508
6509 ERROR:
6510         LOGE("unable to play gapless path. EOS will be posted soon");
6511         return FALSE;
6512 }
6513
6514 static void
6515 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6516 {
6517         GstPad *sinkpad = g_value_get_object (item);
6518         GstElement *element = GST_ELEMENT(user_data);
6519         if (!sinkpad || !element) {
6520                 LOGE("invalid parameter");
6521                 return;
6522         }
6523
6524         LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6525         gst_element_release_request_pad(element, GST_PAD(sinkpad));
6526 }
6527
6528 static gboolean
6529 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6530 {
6531         mmplayer_gst_element_t *sinkbin = NULL;
6532         main_element_id_e concatId = MMPLAYER_M_NUM;
6533         main_element_id_e sinkId = MMPLAYER_M_NUM;
6534         gboolean send_notice = FALSE;
6535         GstElement *element;
6536         GstIterator *iter;
6537
6538         MMPLAYER_FENTER();
6539         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6540
6541         LOGD("type %d", type);
6542
6543         switch (type) {
6544         case MM_PLAYER_TRACK_TYPE_AUDIO:
6545                 concatId = MMPLAYER_M_A_CONCAT;
6546                 sinkId = MMPLAYER_A_BIN;
6547                 sinkbin = player->pipeline->audiobin;
6548                 break;
6549         case MM_PLAYER_TRACK_TYPE_VIDEO:
6550                 concatId = MMPLAYER_M_V_CONCAT;
6551                 sinkId = MMPLAYER_V_BIN;
6552                 sinkbin = player->pipeline->videobin;
6553                 send_notice = TRUE;
6554                 break;
6555         case MM_PLAYER_TRACK_TYPE_TEXT:
6556                 concatId = MMPLAYER_M_T_CONCAT;
6557                 sinkId = MMPLAYER_T_BIN;
6558                 sinkbin = player->pipeline->textbin;
6559                 break;
6560         default:
6561                 LOGE("requested type is not supportable");
6562                 return FALSE;
6563                 break;
6564         }
6565
6566         element = player->pipeline->mainbin[concatId].gst;
6567         if (!element)
6568                 return TRUE;
6569
6570         if ((sinkbin) && (sinkbin[sinkId].gst)) {
6571                 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6572                 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6573                 if (srcpad && sinkpad) {
6574                         /* after getting drained signal there is no data flows, so no need to do pad_block */
6575                         LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6576                         gst_pad_unlink(srcpad, sinkpad);
6577
6578                         /* send custom event to sink pad to handle it at video sink */
6579                         if (send_notice) {
6580                                 LOGD("send custom event to sinkpad");
6581                                 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6582                                 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6583                                 gst_pad_send_event(sinkpad, event);
6584                         }
6585                 }
6586                 gst_object_unref(srcpad);
6587                 gst_object_unref(sinkpad);
6588         }
6589
6590         LOGD("release concat request pad");
6591         /* release and unref requests pad from the selector */
6592         iter = gst_element_iterate_sink_pads(element);
6593         while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6594                 gst_iterator_resync(iter);
6595         gst_iterator_free(iter);
6596
6597         return TRUE;
6598 }
6599
6600 static gboolean
6601 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6602 {
6603         mmplayer_track_t *selector = &player->track[type];
6604         mmplayer_gst_element_t *sinkbin = NULL;
6605         main_element_id_e selectorId = MMPLAYER_M_NUM;
6606         main_element_id_e sinkId = MMPLAYER_M_NUM;
6607         GstPad *srcpad = NULL;
6608         GstPad *sinkpad = NULL;
6609         gboolean send_notice = FALSE;
6610
6611         MMPLAYER_FENTER();
6612         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6613
6614         LOGD("type %d", type);
6615
6616         switch (type) {
6617         case MM_PLAYER_TRACK_TYPE_AUDIO:
6618                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6619                 sinkId = MMPLAYER_A_BIN;
6620                 sinkbin = player->pipeline->audiobin;
6621                 break;
6622         case MM_PLAYER_TRACK_TYPE_VIDEO:
6623                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6624                 sinkId = MMPLAYER_V_BIN;
6625                 sinkbin = player->pipeline->videobin;
6626                 send_notice = TRUE;
6627                 break;
6628         case MM_PLAYER_TRACK_TYPE_TEXT:
6629                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6630                 sinkId = MMPLAYER_T_BIN;
6631                 sinkbin = player->pipeline->textbin;
6632                 break;
6633         default:
6634                 LOGE("requested type is not supportable");
6635                 return FALSE;
6636                 break;
6637         }
6638
6639         if (player->pipeline->mainbin[selectorId].gst) {
6640                 gint n;
6641
6642                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6643
6644                 if (selector->event_probe_id != 0)
6645                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6646                 selector->event_probe_id = 0;
6647
6648                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6649                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6650
6651                         if (srcpad && sinkpad) {
6652                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6653                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6654                                 gst_pad_unlink(srcpad, sinkpad);
6655
6656                                 /* send custom event to sink pad to handle it at video sink */
6657                                 if (send_notice) {
6658                                         LOGD("send custom event to sinkpad");
6659                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6660                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6661                                         gst_pad_send_event(sinkpad, event);
6662                                 }
6663                         }
6664
6665                         gst_object_unref(sinkpad);
6666                         sinkpad = NULL;
6667                 }
6668                 gst_object_unref(srcpad);
6669                 srcpad = NULL;
6670
6671                 LOGD("selector release");
6672
6673                 /* release and unref requests pad from the selector */
6674                 for (n = 0; n < selector->streams->len; n++) {
6675                         GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6676                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6677                 }
6678
6679                 g_ptr_array_set_size(selector->streams, 0);
6680
6681                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6682                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6683
6684                 player->pipeline->mainbin[selectorId].gst = NULL;
6685                 selector = NULL;
6686         }
6687
6688         return TRUE;
6689 }
6690
6691 static void
6692 __mmplayer_deactivate_old_path(mmplayer_t *player)
6693 {
6694         MMPLAYER_FENTER();
6695         MMPLAYER_RETURN_IF_FAIL(player);
6696
6697         if (MMPLAYER_USE_DECODEBIN(player)) {
6698                 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6699                         (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6700                         (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6701                         LOGE("deactivate selector error");
6702                         goto ERROR;
6703                 }
6704         } else {
6705                 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6706                         (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6707                         (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6708                         LOGE("deactivate concat error");
6709                         goto ERROR;
6710                 }
6711         }
6712
6713         _mmplayer_track_destroy(player);
6714         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6715
6716         if (player->streamer) {
6717                 _mm_player_streaming_initialize(player->streamer, FALSE);
6718                 _mm_player_streaming_destroy(player->streamer);
6719                 player->streamer = NULL;
6720         }
6721
6722         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6723         MMPLAYER_FLEAVE();
6724         return;
6725
6726 ERROR:
6727
6728         if (!player->msg_posted) {
6729                 MMMessageParamType msg = {0,};
6730
6731                 /*post error*/
6732                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6733                 LOGE("gapless_uri_play> deactivate error");
6734
6735                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6736                 player->msg_posted = TRUE;
6737         }
6738         return;
6739 }
6740
6741 int
6742 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6743 {
6744         int result = MM_ERROR_NONE;
6745         mmplayer_t *player = (mmplayer_t *)hplayer;
6746         MMPLAYER_FENTER();
6747
6748         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6749         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6750
6751         if (mm_player_set_attribute(hplayer, NULL,
6752                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6753                 LOGE("failed to set attribute");
6754                 result = MM_ERROR_PLAYER_INTERNAL;
6755         } else {
6756                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6757                         LOGE("failed to add the original uri in the uri list.");
6758         }
6759
6760         MMPLAYER_FLEAVE();
6761         return result;
6762 }
6763
6764 int
6765 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6766 {
6767         mmplayer_t *player = (mmplayer_t *)hplayer;
6768         guint num_of_list = 0;
6769
6770         MMPLAYER_FENTER();
6771
6772         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6773         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6774
6775         if (player->pipeline && player->pipeline->textbin) {
6776                 LOGE("subtitle path is enabled.");
6777                 return MM_ERROR_PLAYER_INVALID_STATE;
6778         }
6779
6780         num_of_list = g_list_length(player->uri_info.uri_list);
6781
6782         if (is_first_path) {
6783                 if (num_of_list == 0) {
6784                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6785                         SECURE_LOGD("add original path : %s", uri);
6786                 } else {
6787                         g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6788                         player->uri_info.uri_list = g_list_prepend(
6789                                 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6790                         SECURE_LOGD("change original path : %s", uri);
6791                 }
6792         } else {
6793                 MMHandleType attrs = 0;
6794                 attrs = MMPLAYER_GET_ATTRS(player);
6795
6796                 if (num_of_list == 0) {
6797                         char *original_uri = NULL;
6798
6799                         if (attrs) {
6800                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6801
6802                                 if (!original_uri) {
6803                                         LOGE("there is no original uri.");
6804                                         return MM_ERROR_PLAYER_INVALID_STATE;
6805                                 }
6806
6807                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6808                                 player->uri_info.uri_idx = 0;
6809
6810                                 SECURE_LOGD("add original path at first : %s", original_uri);
6811                         }
6812                 }
6813
6814                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6815                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6816         }
6817
6818         MMPLAYER_FLEAVE();
6819         return MM_ERROR_NONE;
6820 }
6821
6822 int
6823 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6824 {
6825         mmplayer_t *player = (mmplayer_t *)hplayer;
6826         char *next_uri = NULL;
6827         guint num_of_list = 0;
6828
6829         MMPLAYER_FENTER();
6830         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6831
6832         num_of_list = g_list_length(player->uri_info.uri_list);
6833
6834         if (num_of_list > 0) {
6835                 gint uri_idx = player->uri_info.uri_idx;
6836
6837                 if (uri_idx < num_of_list - 1)
6838                         uri_idx++;
6839                 else
6840                         uri_idx = 0;
6841
6842                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6843                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6844
6845                 *uri = g_strdup(next_uri);
6846         }
6847
6848         MMPLAYER_FLEAVE();
6849         return MM_ERROR_NONE;
6850 }
6851
6852 void
6853 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6854         GstCaps *caps, gpointer data)
6855 {
6856         mmplayer_t *player = (mmplayer_t *)data;
6857         const gchar *klass = NULL;
6858         const gchar *mime = NULL;
6859         gchar *caps_str = NULL;
6860
6861         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6862         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6863         caps_str = gst_caps_to_string(caps);
6864
6865         LOGW("unknown type of caps : %s from %s",
6866                                         caps_str, GST_ELEMENT_NAME(elem));
6867
6868         MMPLAYER_FREEIF(caps_str);
6869
6870         /* There is no available codec. */
6871         __mmplayer_check_not_supported_codec(player, klass, mime);
6872 }
6873
6874 gboolean
6875 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6876         GstCaps *caps, gpointer data)
6877 {
6878         mmplayer_t *player = (mmplayer_t *)data;
6879         const char *mime = NULL;
6880         gboolean ret = TRUE;
6881
6882         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6883         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6884
6885         if (g_str_has_prefix(mime, "audio")) {
6886                 GstStructure *caps_structure = NULL;
6887                 gint samplerate = 0;
6888                 gint channels = 0;
6889                 gchar *caps_str = NULL;
6890
6891                 caps_structure = gst_caps_get_structure(caps, 0);
6892                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6893                 gst_structure_get_int(caps_structure, "channels", &channels);
6894
6895                 if ((channels > 0 && samplerate == 0)) {
6896                         LOGD("exclude audio...");
6897                         ret = FALSE;
6898                 }
6899
6900                 caps_str = gst_caps_to_string(caps);
6901                 /* set it directly because not sent by TAG */
6902                 if (g_strrstr(caps_str, "mobile-xmf"))
6903                         mm_player_set_attribute((MMHandleType)player, NULL,
6904                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6905
6906                 MMPLAYER_FREEIF(caps_str);
6907         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6908                 LOGD("already video linked");
6909                 ret = FALSE;
6910         } else {
6911                 LOGD("found new stream");
6912         }
6913
6914         return ret;
6915 }
6916
6917 static gboolean
6918 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6919 {
6920         gboolean ret = FALSE;
6921         GDBusConnection *conn = NULL;
6922         GError *err = NULL;
6923         GVariant *result = NULL;
6924         const gchar *dbus_device_type = NULL;
6925         const gchar *dbus_ret = NULL;
6926         gint idx = 0;
6927
6928         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6929         if (!conn || err) {
6930                 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6931                 g_error_free(err);
6932                 goto DONE;
6933         }
6934
6935         result = g_dbus_connection_call_sync(conn,
6936                                         "org.pulseaudio.Server",
6937                                         "/org/pulseaudio/StreamManager",
6938                                         "org.pulseaudio.StreamManager",
6939                                         "GetCurrentMediaRoutingPath",
6940                                         g_variant_new("(s)", "out"),
6941                                         G_VARIANT_TYPE("(ss)"),
6942                                         G_DBUS_CALL_FLAGS_NONE,
6943                                         2000,
6944                                         NULL,
6945                                         &err);
6946         if (!result || err) {
6947                 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6948                 g_error_free(err);
6949                 goto DONE;
6950         }
6951
6952         /* device type is listed in stream-map.json at mmfw-sysconf */
6953         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6954
6955         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6956         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6957                 goto DONE;
6958
6959         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6960         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6961                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6962                         LOGD("audio offload is supportable");
6963                         ret = TRUE;
6964                         goto DONE;
6965                 }
6966         }
6967
6968         LOGD("audio offload is not supportable");
6969
6970 DONE:
6971         g_variant_unref(result);
6972         if (conn)
6973                 g_object_unref(conn);
6974
6975         return ret;
6976 }
6977
6978 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6979 {
6980         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6981         gint64 position = 0;
6982
6983         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6984                 player->pipeline && player->pipeline->mainbin);
6985
6986         MMPLAYER_CMD_LOCK(player);
6987         current_state = MMPLAYER_CURRENT_STATE(player);
6988
6989         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6990                 LOGW("getting current position failed in paused");
6991
6992         _mmplayer_unrealize((MMHandleType)player);
6993         _mmplayer_realize((MMHandleType)player);
6994
6995         _mmplayer_set_position((MMHandleType)player, position);
6996
6997         /* async not to be blocked in streaming case */
6998         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6999
7000         _mmplayer_pause((MMHandleType)player);
7001
7002         if (current_state == MM_PLAYER_STATE_PLAYING)
7003                 _mmplayer_start((MMHandleType)player);
7004         MMPLAYER_CMD_UNLOCK(player);
7005
7006         LOGD("rebuilding audio pipeline is completed.");
7007 }
7008
7009 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7010 {
7011         mmplayer_t *player = (mmplayer_t *)user_data;
7012         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7013         gboolean is_supportable = FALSE;
7014
7015         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7016                 LOGW("failed to get device type");
7017         else
7018                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7019
7020         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7021                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7022                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7023                 LOGD("ignore this dev connected info");
7024                 return;
7025         }
7026
7027         is_supportable = __mmplayer_is_audio_offload_device_type(player);
7028         if (player->build_audio_offload == is_supportable) {
7029                 LOGD("keep current pipeline without re-building");
7030                 return;
7031         }
7032
7033         /* rebuild pipeline */
7034         LOGD("re-build pipeline - offload: %d", is_supportable);
7035         player->build_audio_offload = FALSE;
7036         __mmplayer_rebuild_audio_pipeline(player);
7037
7038         return;
7039 }
7040
7041 static gboolean
7042 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7043 {
7044         unsigned int id = 0;
7045
7046         if (player->audio_device_cb_id != 0) {
7047                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7048                 return TRUE;
7049         }
7050
7051         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7052                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7053                 LOGD("added device connected cb (%u)", id);
7054                 player->audio_device_cb_id = id;
7055         } else {
7056                 LOGW("failed to add device connected cb");
7057                 return FALSE;
7058         }
7059
7060         return TRUE;
7061 }
7062
7063 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7064 {
7065         mmplayer_t *player = (mmplayer_t *)hplayer;
7066
7067         MMPLAYER_FENTER();
7068         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7069         MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7070
7071         *activated = player->build_audio_offload;
7072
7073         LOGD("offload activated : %d", (int)*activated);
7074
7075         MMPLAYER_FLEAVE();
7076         return MM_ERROR_NONE;
7077 }
7078
7079 static gboolean
7080 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7081 {
7082         /* NOTE :
7083            this function need to be updated according to the supported media format
7084            @see player->ini.audio_offload_media_format */
7085
7086         if (__mmplayer_is_only_mp3_type(player->type)) {
7087                 LOGD("offload supportable media format type");
7088                 return TRUE;
7089         }
7090
7091         return FALSE;
7092 }
7093
7094 static gboolean
7095 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7096 {
7097         gboolean ret = FALSE;
7098         GstElementFactory *factory = NULL;
7099
7100         MMPLAYER_FENTER();
7101         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7102
7103         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7104         if (!__mmplayer_is_offload_supported_type(player))
7105                 goto DONE;
7106
7107         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7108                 LOGD("there is no audio offload sink");
7109                 goto DONE;
7110         }
7111
7112         if (player->ini.audio_offload_device_type[0][0] == '\0') {
7113                 LOGW("there is no audio device type to support offload");
7114                 goto DONE;
7115         }
7116
7117         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7118         if (!factory) {
7119                 LOGW("there is no installed audio offload sink element");
7120                 goto DONE;
7121         }
7122         gst_object_unref(factory);
7123
7124         if (_mmplayer_acquire_hw_resource(player,
7125                         MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7126                 LOGE("failed to acquire audio offload decoder resource");
7127                 goto DONE;
7128         }
7129
7130         if (!__mmplayer_add_audio_device_connected_cb(player))
7131                 goto DONE;
7132
7133         if (!__mmplayer_is_audio_offload_device_type(player))
7134                 goto DONE;
7135
7136         LOGD("audio offload can be built");
7137         ret = TRUE;
7138
7139 DONE:
7140         if (!ret)
7141                 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7142
7143         MMPLAYER_FLEAVE();
7144         return ret;
7145 }
7146
7147 static GstAutoplugSelectResult
7148 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7149 {
7150         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7151         int audio_offload = 0;
7152
7153         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7154                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7155
7156                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7157                         LOGD("expose audio path to build offload output path");
7158                         player->build_audio_offload = TRUE;
7159                         /* update codec info */
7160                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7161                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7162                         player->audiodec_linked = 1;
7163
7164                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
7165                         goto DONE;
7166                 }
7167
7168                 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7169                                   And need to consider the multi-track audio content.
7170                           There is no HW audio decoder in public. */
7171
7172                 /* set stream information */
7173                 if (!player->audiodec_linked)
7174                         _mmplayer_set_audio_attrs(player, caps);
7175
7176                 /* update codec info */
7177                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7178                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7179                 player->audiodec_linked = 1;
7180
7181         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7182
7183                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7184                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7185
7186                         /* mark video decoder for acquire */
7187                         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7188                                 LOGW("video decoder resource is already acquired, skip it.");
7189                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7190                                 goto DONE;
7191                         }
7192
7193                         if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7194                                 LOGE("failed to acquire video decoder resource");
7195                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7196                                 goto DONE;
7197                         }
7198                         player->interrupted_by_resource = FALSE;
7199                 }
7200
7201                 /* update codec info */
7202                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7203                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7204                 player->videodec_linked = 1;
7205         }
7206
7207 DONE:
7208         return ret;
7209 }
7210
7211 GValueArray *
7212 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7213                 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7214 {
7215 #define DEFAULT_IDX 0xFFFF
7216 #define MIN_FACTORY_NUM 2
7217         mmplayer_t *player = (mmplayer_t *)data;
7218         GValueArray *new_factories = NULL;
7219         GValue val = { 0, };
7220         GstElementFactory *factory = NULL;
7221         const gchar *klass = NULL;
7222         gchar *factory_name = NULL;
7223         guint hw_dec_idx = DEFAULT_IDX;
7224         guint first_sw_dec_idx = DEFAULT_IDX;
7225         guint last_sw_dec_idx = DEFAULT_IDX;
7226         guint new_pos = DEFAULT_IDX;
7227         guint rm_pos = DEFAULT_IDX;
7228         int audio_codec_type;
7229         int video_codec_type;
7230         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7231
7232         if (factories->n_values < MIN_FACTORY_NUM)
7233                 return NULL;
7234
7235         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7236         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7237
7238 #ifdef __DEBUG__
7239         LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7240 #endif
7241         for (int i = 0 ; i < factories->n_values ; i++) {
7242                 gchar *hw_dec_info = NULL;
7243                 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7244
7245                 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7246                 if (!factory) {
7247                         LOGW("failed to get factory object");
7248                         continue;
7249                 }
7250                 klass = gst_element_factory_get_klass(factory);
7251                 factory_name = GST_OBJECT_NAME(factory);
7252
7253 #ifdef __DEBUG__
7254                 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7255 #endif
7256                 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7257                         if (!player->need_audio_dec_sorting) {
7258                                 LOGD("sorting is not required");
7259                                 return NULL;
7260                         }
7261                         codec_type = audio_codec_type;
7262                         hw_dec_info = player->ini.audiocodec_element_hw;
7263                         sw_dec_info = player->ini.audiocodec_element_sw;
7264                 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7265                         if (!player->need_video_dec_sorting) {
7266                                 LOGD("sorting is not required");
7267                                 return NULL;
7268                         }
7269                         codec_type = video_codec_type;
7270                         hw_dec_info = player->ini.videocodec_element_hw;
7271                         sw_dec_info = player->ini.videocodec_element_sw;
7272                 } else {
7273                         continue;
7274                 }
7275
7276                 if (g_strrstr(factory_name, hw_dec_info)) {
7277                         hw_dec_idx = i;
7278                 } else {
7279                         for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7280                                 if (strstr(factory_name, sw_dec_info[j])) {
7281                                         last_sw_dec_idx = i;
7282                                         if (first_sw_dec_idx == DEFAULT_IDX) {
7283                                                 first_sw_dec_idx = i;
7284                                         }
7285                                 }
7286                         }
7287
7288                         if (first_sw_dec_idx == DEFAULT_IDX)
7289                                 LOGW("unknown codec %s", factory_name);
7290                 }
7291         }
7292
7293         if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7294                 return NULL;
7295
7296         if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7297                 if (hw_dec_idx < first_sw_dec_idx)
7298                         return NULL;
7299                 new_pos = first_sw_dec_idx;
7300                 rm_pos = hw_dec_idx + 1;
7301         } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7302                 if (last_sw_dec_idx < hw_dec_idx)
7303                         return NULL;
7304                 new_pos = last_sw_dec_idx + 1;
7305                 rm_pos = hw_dec_idx;
7306         } else {
7307                 return NULL;
7308         }
7309
7310         /* change position - insert H/W decoder according to the new position */
7311         factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7312         if (!factory) {
7313                 LOGW("failed to get factory object");
7314                 return NULL;
7315         }
7316         new_factories = g_value_array_copy(factories);
7317         g_value_init (&val, G_TYPE_OBJECT);
7318         g_value_set_object (&val, factory);
7319         g_value_array_insert(new_factories, new_pos, &val);
7320         g_value_unset (&val);
7321         g_value_array_remove(new_factories, rm_pos);    /* remove previous H/W element */
7322
7323         for (int i = 0 ; i < new_factories->n_values ; i++) {
7324                 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7325                 if (factory)
7326                         LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7327                                 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7328                 else
7329                         LOGE("[Re-arranged] failed to get factory object");
7330         }
7331
7332         return new_factories;
7333 }
7334
7335 gint
7336 _mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7337         GstCaps *caps, GstElementFactory *factory, gpointer data)
7338 {
7339         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7340         mmplayer_t *player = (mmplayer_t *)data;
7341
7342         gchar *factory_name = NULL;
7343         gchar *caps_str = NULL;
7344         const gchar *klass = NULL;
7345         gint idx = 0;
7346
7347         factory_name = GST_OBJECT_NAME(factory);
7348         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7349         caps_str = gst_caps_to_string(caps);
7350
7351         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7352
7353         /* store type string */
7354         if (player->type == NULL) {
7355                 player->type = gst_caps_to_string(caps);
7356                 __mmplayer_update_content_type_info(player);
7357         }
7358
7359         /* filtering exclude keyword */
7360         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7361                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7362                         LOGW("skipping [%s] by exclude keyword [%s]",
7363                                         factory_name, player->ini.exclude_element_keyword[idx]);
7364
7365                         result = GST_AUTOPLUG_SELECT_SKIP;
7366                         goto DONE;
7367                 }
7368         }
7369
7370         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7371                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7372                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7373                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7374                         result = GST_AUTOPLUG_SELECT_SKIP;
7375                         goto DONE;
7376                 }
7377         }
7378
7379         /* exclude webm format */
7380         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7381          * because webm format is not supportable.
7382          * If webm is disabled in "autoplug-continue", there is no state change
7383          * failure or error because the decodebin will expose the pad directly.
7384          * It make MSL invoke _prepare_async_callback.
7385          * So, we need to disable webm format in "autoplug-select" */
7386         if (caps_str && strstr(caps_str, "webm")) {
7387                 LOGW("webm is not supported");
7388                 result = GST_AUTOPLUG_SELECT_SKIP;
7389                 goto DONE;
7390         }
7391
7392         /* check factory class for filtering */
7393         /* NOTE : msl don't need to use image plugins.
7394          * So, those plugins should be skipped for error handling.
7395          */
7396         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7397                 LOGD("skipping [%s] by not required", factory_name);
7398                 result = GST_AUTOPLUG_SELECT_SKIP;
7399                 goto DONE;
7400         }
7401
7402         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7403                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7404                 // TO CHECK : subtitle if needed, add subparse exception.
7405                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7406                 result = GST_AUTOPLUG_SELECT_SKIP;
7407                 goto DONE;
7408         }
7409
7410         if (g_strrstr(factory_name, "mpegpsdemux")) {
7411                 LOGD("skipping PS container - not support");
7412                 result = GST_AUTOPLUG_SELECT_SKIP;
7413                 goto DONE;
7414         }
7415
7416         if (g_strrstr(factory_name, "mssdemux"))
7417                 player->smooth_streaming = TRUE;
7418
7419         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7420                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7421                 gint stype = 0;
7422                 gint width = 0;
7423                 GstStructure *str = NULL;
7424                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7425
7426                 /* don't make video because of not required */
7427                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7428                         (!player->set_mode.video_export)) {
7429                         LOGD("no need video decoding, expose pad");
7430                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7431                         goto DONE;
7432                 }
7433
7434                 /* get w/h for omx state-tune */
7435                 /* FIXME: deprecated? */
7436                 str = gst_caps_get_structure(caps, 0);
7437                 gst_structure_get_int(str, "width", &width);
7438
7439                 if (width != 0) {
7440                         if (player->v_stream_caps) {
7441                                 gst_caps_unref(player->v_stream_caps);
7442                                 player->v_stream_caps = NULL;
7443                         }
7444
7445                         player->v_stream_caps = gst_caps_copy(caps);
7446                         LOGD("take caps for video state tune");
7447                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7448                 }
7449         }
7450
7451         if (g_strrstr(klass, "Codec/Decoder")) {
7452                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7453                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7454                         LOGW("skip add decoder");
7455                         goto DONE;
7456                 }
7457         }
7458
7459 DONE:
7460         MMPLAYER_FREEIF(caps_str);
7461
7462         return result;
7463 }
7464
7465 void
7466 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7467         gpointer data)
7468 {
7469         //mmplayer_t *player = (mmplayer_t *)data;
7470         GstCaps *caps = NULL;
7471
7472         LOGD("[Decodebin2] pad-removed signal");
7473
7474         caps = gst_pad_query_caps(new_pad, NULL);
7475         if (!caps) {
7476                 LOGW("query caps is NULL");
7477                 return;
7478         }
7479
7480         gchar *caps_str = NULL;
7481         caps_str = gst_caps_to_string(caps);
7482
7483         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7484
7485         MMPLAYER_FREEIF(caps_str);
7486         gst_caps_unref(caps);
7487 }
7488
7489 void
7490 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7491 {
7492         mmplayer_t *player = (mmplayer_t *)data;
7493
7494         MMPLAYER_FENTER();
7495         MMPLAYER_RETURN_IF_FAIL(player);
7496
7497         LOGD("got about to finish signal");
7498
7499         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7500                 LOGW("Fail to get cmd lock");
7501                 return;
7502         }
7503
7504         if (!__mmplayer_verify_gapless_play_path(player)) {
7505                 LOGD("decoding is finished.");
7506                 MMPLAYER_CMD_UNLOCK(player);
7507                 return;
7508         }
7509
7510         _mmplayer_set_reconfigure_state(player, TRUE);
7511         MMPLAYER_CMD_UNLOCK(player);
7512
7513         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7514         __mmplayer_deactivate_old_path(player);
7515
7516         MMPLAYER_FLEAVE();
7517 }
7518
7519 void
7520 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7521 {
7522         mmplayer_t *player = (mmplayer_t *)data;
7523         GstIterator *iter = NULL;
7524         GValue item = { 0, };
7525         GstPad *pad = NULL;
7526         gboolean done = FALSE;
7527         gboolean is_all_drained = TRUE;
7528
7529         MMPLAYER_FENTER();
7530         MMPLAYER_RETURN_IF_FAIL(player);
7531
7532         LOGD("got drained signal");
7533
7534         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7535                 LOGW("Fail to get cmd lock");
7536                 return;
7537         }
7538
7539         if (!__mmplayer_verify_gapless_play_path(player)) {
7540                 LOGD("decoding is finished.");
7541                 MMPLAYER_CMD_UNLOCK(player);
7542                 return;
7543         }
7544
7545         _mmplayer_set_reconfigure_state(player, TRUE);
7546         MMPLAYER_CMD_UNLOCK(player);
7547
7548         /* check decodebin src pads whether they received EOS or not */
7549         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7550
7551         while (!done) {
7552                 switch (gst_iterator_next(iter, &item)) {
7553                 case GST_ITERATOR_OK:
7554                         pad = g_value_get_object(&item);
7555                         if (pad && !GST_PAD_IS_EOS(pad)) {
7556                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7557                                 is_all_drained = FALSE;
7558                                 break;
7559                         }
7560                         g_value_reset(&item);
7561                         break;
7562                 case GST_ITERATOR_RESYNC:
7563                         gst_iterator_resync(iter);
7564                         break;
7565                 case GST_ITERATOR_ERROR:
7566                 case GST_ITERATOR_DONE:
7567                         done = TRUE;
7568                         break;
7569                 }
7570         }
7571         g_value_unset(&item);
7572         gst_iterator_free(iter);
7573
7574         if (!is_all_drained) {
7575                 LOGD("Wait util the all pads get EOS.");
7576                 MMPLAYER_FLEAVE();
7577                 return;
7578         }
7579
7580         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7581         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7582
7583         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7584         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7585         __mmplayer_deactivate_old_path(player);
7586
7587         MMPLAYER_FLEAVE();
7588 }
7589
7590 void
7591 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7592 {
7593         mmplayer_t *player = (mmplayer_t *)data;
7594         const gchar *klass = NULL;
7595         gchar *factory_name = NULL;
7596
7597         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7598         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7599
7600         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7601
7602         if (__mmplayer_add_dump_buffer_probe(player, element))
7603                 LOGD("add buffer probe");
7604
7605         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7606                 gchar *selected = NULL;
7607                 selected = g_strdup(GST_ELEMENT_NAME(element));
7608                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7609
7610                 /* update codec info */
7611                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7612                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7613                 player->audiodec_linked = 1;
7614         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7615                 /* update codec info */
7616                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7617                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7618                 player->videodec_linked = 1;
7619         }
7620
7621         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7622                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7623                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7624
7625                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7626                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7627
7628                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7629                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7630                                                 "max-video-width", player->adaptive_info.limit.width,
7631                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7632
7633         } else if (g_strrstr(klass, "Demuxer")) {
7634 #ifdef __DEBUG__
7635                 LOGD("plugged element is demuxer. take it");
7636 #endif
7637                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7638                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7639         }
7640
7641         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7642                 int surface_type = 0;
7643
7644                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7645         }
7646
7647         // to support trust-zone only
7648         if (g_strrstr(factory_name, "asfdemux")) {
7649                 LOGD("set file-location %s", player->profile.uri);
7650                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7651         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7652                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7653                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7654         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7655                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7656                         (__mmplayer_is_only_mp3_type(player->type))) {
7657                         LOGD("[mpegaudioparse] set streaming pull mode.");
7658                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7659                 }
7660         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7661                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7662         }
7663
7664         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7665                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7666                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7667
7668                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7669                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7670
7671                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7672                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7673                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7674                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7675                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7676                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7677                 }
7678
7679         }
7680
7681         return;
7682 }
7683
7684 static void
7685 __mmplayer_release_misc(mmplayer_t *player)
7686 {
7687         int i;
7688         bool cur_mode = player->set_mode.rich_audio;
7689         MMPLAYER_FENTER();
7690
7691         MMPLAYER_RETURN_IF_FAIL(player);
7692
7693         player->sent_bos = FALSE;
7694         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7695
7696         player->seek_state = MMPLAYER_SEEK_NONE;
7697
7698         player->total_bitrate = 0;
7699         player->total_maximum_bitrate = 0;
7700
7701         player->not_found_demuxer = 0;
7702
7703         player->last_position = 0;
7704         player->duration = 0;
7705         player->http_content_size = 0;
7706         player->not_supported_codec = MISSING_PLUGIN_NONE;
7707         player->can_support_codec = FOUND_PLUGIN_NONE;
7708         player->pending_seek.is_pending = false;
7709         player->pending_seek.pos = 0;
7710         player->msg_posted = FALSE;
7711         player->has_many_types = FALSE;
7712         player->is_subtitle_force_drop = FALSE;
7713         player->play_subtitle = FALSE;
7714         player->adjust_subtitle_pos = 0;
7715         player->has_closed_caption = FALSE;
7716         player->set_mode.video_export = false;
7717         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7718         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7719         /* recover mode */
7720         player->set_mode.rich_audio = cur_mode;
7721
7722         if (player->audio_device_cb_id > 0 &&
7723                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7724                 LOGW("failed to remove audio device_connected_callback");
7725         player->audio_device_cb_id = 0;
7726
7727         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7728                 player->bitrate[i] = 0;
7729                 player->maximum_bitrate[i] = 0;
7730         }
7731
7732         /* free memory related to audio effect */
7733         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7734
7735         if (player->adaptive_info.var_list) {
7736                 g_list_free_full(player->adaptive_info.var_list, g_free);
7737                 player->adaptive_info.var_list = NULL;
7738         }
7739
7740         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7741         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7742         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7743
7744         /* Reset video360 settings to their defaults in case if the pipeline is to be
7745          * re-created.
7746          * */
7747         player->video360_metadata.is_spherical = -1;
7748         player->is_openal_plugin_used = FALSE;
7749
7750         player->is_content_spherical = FALSE;
7751         player->is_video360_enabled = TRUE;
7752         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7753         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7754         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7755         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7756         player->video360_zoom = 1.0f;
7757         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7758         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7759
7760         player->sound.rg_enable = false;
7761
7762         __mmplayer_initialize_video_roi(player);
7763         MMPLAYER_FLEAVE();
7764 }
7765
7766 static void
7767 __mmplayer_release_misc_post(mmplayer_t *player)
7768 {
7769         gchar *original_uri = NULL;
7770         MMPLAYER_FENTER();
7771
7772         /* player->pipeline is already released before. */
7773         MMPLAYER_RETURN_IF_FAIL(player);
7774
7775         player->video_decoded_cb = NULL;
7776         player->video_decoded_cb_user_param = NULL;
7777         player->video_stream_prerolled = false;
7778
7779         player->audio_decoded_cb = NULL;
7780         player->audio_decoded_cb_user_param = NULL;
7781         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7782
7783         player->audio_stream_changed_cb = NULL;
7784         player->audio_stream_changed_cb_user_param = NULL;
7785
7786         mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7787
7788         /* clean found audio decoders */
7789         if (player->audio_decoders) {
7790                 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7791                 player->audio_decoders = NULL;
7792         }
7793
7794         /* clean the uri list except original uri */
7795         if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7796                 GList *tmp = NULL;
7797                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7798                 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7799                 g_list_free_full(tmp, (GDestroyNotify)g_free);
7800
7801                 if (!original_uri)
7802                         LOGW("failed to get original uri info");
7803
7804                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7805                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7806                 MMPLAYER_FREEIF(original_uri);
7807         }
7808
7809         /* clear the audio stream buffer list */
7810         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7811
7812         /* clear the video stream bo list */
7813         __mmplayer_video_stream_destroy_bo_list(player);
7814         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7815
7816         if (player->profile.input_mem.buf) {
7817                 free(player->profile.input_mem.buf);
7818                 player->profile.input_mem.buf = NULL;
7819         }
7820         player->profile.input_mem.len = 0;
7821         player->profile.input_mem.offset = 0;
7822
7823         player->uri_info.uri_idx = 0;
7824         MMPLAYER_FLEAVE();
7825 }
7826
7827 gboolean
7828 __mmplayer_check_subtitle(mmplayer_t *player)
7829 {
7830         MMHandleType attrs = 0;
7831         char *subtitle_uri = NULL;
7832
7833         MMPLAYER_FENTER();
7834
7835         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7836
7837         /* get subtitle attribute */
7838         attrs = MMPLAYER_GET_ATTRS(player);
7839         if (!attrs)
7840                 return FALSE;
7841
7842         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7843         if (!subtitle_uri || !strlen(subtitle_uri))
7844                 return FALSE;
7845
7846         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7847         player->is_external_subtitle_present = TRUE;
7848
7849         MMPLAYER_FLEAVE();
7850
7851         return TRUE;
7852 }
7853
7854 void
7855 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7856 {
7857         MMPLAYER_RETURN_IF_FAIL(player);
7858
7859         if (player->eos_timer) {
7860                 LOGD("cancel eos timer");
7861                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7862                 player->eos_timer = 0;
7863         }
7864
7865         return;
7866 }
7867
7868 static void
7869 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7870 {
7871         MMPLAYER_FENTER();
7872
7873         MMPLAYER_RETURN_IF_FAIL(player);
7874         MMPLAYER_RETURN_IF_FAIL(sink);
7875
7876         if (first)
7877                 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7878         else
7879                 player->sink_elements = g_list_append(player->sink_elements, sink);
7880
7881         MMPLAYER_FLEAVE();
7882 }
7883
7884 static void
7885 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7886 {
7887         MMPLAYER_FENTER();
7888
7889         MMPLAYER_RETURN_IF_FAIL(player);
7890         MMPLAYER_RETURN_IF_FAIL(sink);
7891
7892         player->sink_elements = g_list_remove(player->sink_elements, sink);
7893
7894         MMPLAYER_FLEAVE();
7895 }
7896
7897 void
7898 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7899         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7900 {
7901         mmplayer_signal_item_t *item = NULL;
7902
7903         MMPLAYER_FENTER();
7904         MMPLAYER_RETURN_IF_FAIL(player);
7905
7906         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7907                 LOGE("invalid signal type [%d]", type);
7908                 return;
7909         }
7910
7911         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7912         if (!item) {
7913                 LOGE("cannot connect signal [%s]", signal);
7914                 return;
7915         }
7916
7917         item->obj = object;
7918         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7919         player->signals[type] = g_list_append(player->signals[type], item);
7920
7921         MMPLAYER_FLEAVE();
7922         return;
7923 }
7924
7925 /* NOTE : be careful with calling this api. please refer to below glib comment
7926  * glib comment : Note that there is a bug in GObject that makes this function much
7927  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7928  * will no longer be called, but, the signal handler is not currently disconnected.
7929  * If the instance is itself being freed at the same time than this doesn't matter,
7930  * since the signal will automatically be removed, but if instance persists,
7931  * then the signal handler will leak. You should not remove the signal yourself
7932  * because in a future versions of GObject, the handler will automatically be
7933  * disconnected.
7934  *
7935  * It's possible to work around this problem in a way that will continue to work
7936  * with future versions of GObject by checking that the signal handler is still
7937  * connected before disconnected it:
7938  *
7939  *  if (g_signal_handler_is_connected(instance, id))
7940  *    g_signal_handler_disconnect(instance, id);
7941  */
7942 static void
7943 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7944 {
7945         GList *sig_list = NULL;
7946         mmplayer_signal_item_t *item = NULL;
7947
7948         MMPLAYER_FENTER();
7949
7950         MMPLAYER_RETURN_IF_FAIL(player);
7951
7952         LOGD("release signals type : %d", type);
7953
7954         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7955                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7956                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7957                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7958                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7959                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7960                 return;
7961         }
7962
7963         sig_list = player->signals[type];
7964
7965         for (; sig_list; sig_list = sig_list->next) {
7966                 item = sig_list->data;
7967
7968                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7969                         if (g_signal_handler_is_connected(item->obj, item->sig))
7970                                 g_signal_handler_disconnect(item->obj, item->sig);
7971                 }
7972
7973                 MMPLAYER_FREEIF(item);
7974         }
7975
7976         g_list_free(player->signals[type]);
7977         player->signals[type] = NULL;
7978
7979         MMPLAYER_FLEAVE();
7980
7981         return;
7982 }
7983
7984 int
7985 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7986 {
7987         mmplayer_t *player = 0;
7988         int prev_display_surface_type = 0;
7989
7990         MMPLAYER_FENTER();
7991
7992         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7993
7994         player = MM_PLAYER_CAST(handle);
7995
7996         /* check video sinkbin is created */
7997         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7998                 LOGW("Videosink is already created");
7999                 return MM_ERROR_NONE;
8000         }
8001
8002         LOGD("videosink element is not yet ready");
8003
8004         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8005                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8006                 MMPLAYER_FLEAVE();
8007                 return MM_ERROR_INVALID_ARGUMENT;
8008         }
8009
8010         /* load previous attributes */
8011         if (player->attrs) {
8012                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8013                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8014                 if (prev_display_surface_type == surface_type) {
8015                         LOGD("incoming display surface type is same as previous one, do nothing..");
8016                         MMPLAYER_FLEAVE();
8017                         return MM_ERROR_NONE;
8018                 }
8019         } else {
8020                 LOGE("failed to load attributes");
8021                 MMPLAYER_FLEAVE();
8022                 return MM_ERROR_PLAYER_INTERNAL;
8023         }
8024
8025         /* videobin is not created yet, so we just set attributes related to display surface */
8026         LOGD("store display attribute for given surface type(%d)", surface_type);
8027         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8028                         "display_overlay", wl_surface_id, NULL);
8029
8030         MMPLAYER_FLEAVE();
8031         return MM_ERROR_NONE;
8032 }
8033
8034 /* Note : if silent is true, then subtitle would not be displayed. :*/
8035 int
8036 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8037 {
8038         mmplayer_t *player = (mmplayer_t *)hplayer;
8039
8040         MMPLAYER_FENTER();
8041
8042         /* check player handle */
8043         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8044
8045         player->set_mode.subtitle_off = silent;
8046
8047         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8048
8049         MMPLAYER_FLEAVE();
8050
8051         return MM_ERROR_NONE;
8052 }
8053
8054 int
8055 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8056 {
8057         mmplayer_gst_element_t *mainbin = NULL;
8058         mmplayer_gst_element_t *textbin = NULL;
8059         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8060         GstState current_state = GST_STATE_VOID_PENDING;
8061         GstState element_state = GST_STATE_VOID_PENDING;
8062         GstState element_pending_state = GST_STATE_VOID_PENDING;
8063         gint64 time = 0;
8064         GstEvent *event = NULL;
8065         int result = MM_ERROR_NONE;
8066
8067         GstClock *curr_clock = NULL;
8068         GstClockTime base_time, start_time, curr_time;
8069
8070
8071         MMPLAYER_FENTER();
8072
8073         /* check player handle */
8074         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8075                                                                 player->pipeline &&
8076                                                                 player->pipeline->mainbin &&
8077                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8078
8079         mainbin = player->pipeline->mainbin;
8080         textbin = player->pipeline->textbin;
8081
8082         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8083
8084         // sync clock with current pipeline
8085         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8086         curr_time = gst_clock_get_time(curr_clock);
8087
8088         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8089         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8090
8091         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8092                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8093
8094         if (current_state > GST_STATE_READY) {
8095                 // sync state with current pipeline
8096                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8097                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8098                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8099
8100                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8101                 if (GST_STATE_CHANGE_FAILURE == ret) {
8102                         LOGE("fail to state change.");
8103                         result = MM_ERROR_PLAYER_INTERNAL;
8104                         goto ERROR;
8105                 }
8106         }
8107         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8108         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8109
8110         if (curr_clock) {
8111                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8112                 gst_object_unref(curr_clock);
8113         }
8114
8115         // seek to current position
8116         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8117                 result = MM_ERROR_PLAYER_INVALID_STATE;
8118                 LOGE("gst_element_query_position failed, invalid state");
8119                 goto ERROR;
8120         }
8121
8122         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8123         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);
8124         if (event) {
8125                 _mmplayer_gst_send_event_to_sink(player, event);
8126         } else {
8127                 result = MM_ERROR_PLAYER_INTERNAL;
8128                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8129                 goto ERROR;
8130         }
8131
8132         /* sync state with current pipeline */
8133         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8134         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8135         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8136
8137         return MM_ERROR_NONE;
8138
8139 ERROR:
8140         /* release text pipeline resource */
8141         player->textsink_linked = 0;
8142
8143         /* release signal */
8144         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8145
8146         /* release textbin with it's children */
8147         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8148         MMPLAYER_FREEIF(player->pipeline->textbin);
8149         player->pipeline->textbin = NULL;
8150
8151         /* release subtitle elem */
8152         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8153         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8154
8155         return result;
8156 }
8157
8158 static int
8159 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8160 {
8161         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8162         GstState current_state = GST_STATE_VOID_PENDING;
8163
8164         MMHandleType attrs = 0;
8165         mmplayer_gst_element_t *mainbin = NULL;
8166         mmplayer_gst_element_t *textbin = NULL;
8167
8168         gchar *subtitle_uri = NULL;
8169         int result = MM_ERROR_NONE;
8170         const gchar *charset = NULL;
8171
8172         MMPLAYER_FENTER();
8173
8174         /* check player handle */
8175         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8176                                                                 player->pipeline &&
8177                                                                 player->pipeline->mainbin &&
8178                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8179         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8180
8181         mainbin = player->pipeline->mainbin;
8182         textbin = player->pipeline->textbin;
8183
8184         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8185         if (current_state < GST_STATE_READY) {
8186                 result = MM_ERROR_PLAYER_INVALID_STATE;
8187                 LOGE("Pipeline is not in proper state");
8188                 goto EXIT;
8189         }
8190
8191         attrs = MMPLAYER_GET_ATTRS(player);
8192         if (!attrs) {
8193                 LOGE("cannot get content attribute");
8194                 result = MM_ERROR_PLAYER_INTERNAL;
8195                 goto EXIT;
8196         }
8197
8198         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8199         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8200                 LOGE("subtitle uri is not proper filepath");
8201                 result = MM_ERROR_PLAYER_INVALID_URI;
8202                 goto EXIT;
8203         }
8204
8205         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8206                 LOGE("failed to get storage info of subtitle path");
8207                 result = MM_ERROR_PLAYER_INVALID_URI;
8208                 goto EXIT;
8209         }
8210
8211         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8212         SECURE_LOGD("new subtitle file path is [%s]", filepath);
8213
8214         if (!strcmp(filepath, subtitle_uri)) {
8215                 LOGD("subtitle path is not changed");
8216                 goto EXIT;
8217         } else {
8218                 if (mm_player_set_attribute((MMHandleType)player, NULL,
8219                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8220                         LOGE("failed to set attribute");
8221                         goto EXIT;
8222                 }
8223         }
8224
8225         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8226         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8227         player->subtitle_language_list = NULL;
8228         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8229
8230         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8231         if (ret != GST_STATE_CHANGE_SUCCESS) {
8232                 LOGE("failed to change state of textbin to READY");
8233                 result = MM_ERROR_PLAYER_INTERNAL;
8234                 goto EXIT;
8235         }
8236
8237         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8238         if (ret != GST_STATE_CHANGE_SUCCESS) {
8239                 LOGE("failed to change state of subparse to READY");
8240                 result = MM_ERROR_PLAYER_INTERNAL;
8241                 goto EXIT;
8242         }
8243
8244         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8245         if (ret != GST_STATE_CHANGE_SUCCESS) {
8246                 LOGE("failed to change state of filesrc to READY");
8247                 result = MM_ERROR_PLAYER_INTERNAL;
8248                 goto EXIT;
8249         }
8250
8251         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8252
8253         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8254
8255         charset = _mmplayer_get_charset(filepath);
8256         if (charset) {
8257                 LOGD("detected charset is %s", charset);
8258                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8259         }
8260
8261         result = _mmplayer_sync_subtitle_pipeline(player);
8262
8263 EXIT:
8264         MMPLAYER_FLEAVE();
8265         return result;
8266 }
8267
8268 /* API to switch between external subtitles */
8269 int
8270 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8271 {
8272         int result = MM_ERROR_NONE;
8273         mmplayer_t *player = (mmplayer_t *)hplayer;
8274         char *path = NULL;
8275
8276         MMPLAYER_FENTER();
8277
8278         /* check player handle */
8279         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8280
8281         /* filepath can be null in idle state */
8282         if (filepath) {
8283                 /* check file path */
8284                 if ((path = strstr(filepath, "file://")))
8285                         result = _mmplayer_exist_file_path(path + 7);
8286                 else
8287                         result = _mmplayer_exist_file_path(filepath);
8288
8289                 if (result != MM_ERROR_NONE) {
8290                         LOGE("invalid subtitle path 0x%X", result);
8291                         return result; /* file not found or permission denied */
8292                 }
8293         }
8294
8295         if (!player->pipeline) {
8296                 /* IDLE state */
8297                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8298                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8299                         LOGE("failed to set attribute");
8300                         return MM_ERROR_PLAYER_INTERNAL;
8301                 }
8302         } else {
8303                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8304                 /* check filepath */
8305                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8306
8307                 if (!__mmplayer_check_subtitle(player)) {
8308                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8309                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8310                                 LOGE("failed to set attribute");
8311                                 return MM_ERROR_PLAYER_INTERNAL;
8312                         }
8313
8314                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8315                                 LOGE("fail to create text pipeline");
8316                                 return MM_ERROR_PLAYER_INTERNAL;
8317                         }
8318
8319                         result = _mmplayer_sync_subtitle_pipeline(player);
8320                 } else {
8321                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8322                 }
8323
8324                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8325                 player->is_external_subtitle_added_now = TRUE;
8326
8327                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8328                 if (!player->subtitle_language_list) {
8329                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8330                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8331                                 LOGW("subtitle language list is not updated yet");
8332                 }
8333                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8334         }
8335
8336         MMPLAYER_FLEAVE();
8337         return result;
8338 }
8339
8340 static int
8341 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8342 {
8343         guint active_idx = 0;
8344         GstStream *stream = NULL;
8345         GList *streams = NULL;
8346         GstEvent *ev = NULL;
8347         GstCaps *caps = NULL;
8348
8349         LOGD("Switching Streams... type: %d, index: %d", type, index);
8350
8351         player->track[type].active_track_index = index;
8352
8353         for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8354                 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8355                 if (player->track[i].total_track_num > 0) {
8356                         active_idx = player->track[i].active_track_index;
8357                         stream = g_ptr_array_index(player->track[i].streams, active_idx);
8358                         streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8359                         LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8360
8361                         if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8362                                 caps = gst_stream_get_caps(stream);
8363                                 if (caps) {
8364                                         _mmplayer_set_audio_attrs(player, caps);
8365                                         gst_caps_unref(caps);
8366                                 }
8367                         }
8368                 }
8369         }
8370
8371         ev = gst_event_new_select_streams(streams);
8372         gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8373         g_list_free(streams);
8374
8375         return MM_ERROR_NONE;
8376 }
8377
8378 static int
8379 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8380 {
8381         int result = MM_ERROR_NONE;
8382         gchar *change_pad_name = NULL;
8383         GstPad *sinkpad = NULL;
8384         mmplayer_gst_element_t *mainbin = NULL;
8385         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8386         GstCaps *caps = NULL;
8387         gint total_track_num = 0;
8388
8389         MMPLAYER_FENTER();
8390
8391         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8392                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8393
8394         LOGD("Change Track(%d) to %d", type, index);
8395
8396         mainbin = player->pipeline->mainbin;
8397
8398         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8399                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8400         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8401                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8402         } else {
8403                 /* Changing Video Track is not supported. */
8404                 LOGE("Track Type Error");
8405                 goto EXIT;
8406         }
8407
8408         if (mainbin[elem_idx].gst == NULL) {
8409                 result = MM_ERROR_PLAYER_NO_OP;
8410                 LOGD("Req track doesn't exist");
8411                 goto EXIT;
8412         }
8413
8414         total_track_num = player->track[type].total_track_num;
8415         if (total_track_num <= 0) {
8416                 result = MM_ERROR_PLAYER_NO_OP;
8417                 LOGD("Language list is not available");
8418                 goto EXIT;
8419         }
8420
8421         if ((index < 0) || (index >= total_track_num)) {
8422                 result = MM_ERROR_INVALID_ARGUMENT;
8423                 LOGD("Not a proper index : %d", index);
8424                 goto EXIT;
8425         }
8426
8427         /*To get the new pad from the selector*/
8428         change_pad_name = g_strdup_printf("sink_%u", index);
8429         if (change_pad_name == NULL) {
8430                 result = MM_ERROR_PLAYER_INTERNAL;
8431                 LOGD("Pad does not exists");
8432                 goto EXIT;
8433         }
8434
8435         LOGD("new active pad name: %s", change_pad_name);
8436
8437         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8438         if (sinkpad == NULL) {
8439                 LOGD("sinkpad is NULL");
8440                 result = MM_ERROR_PLAYER_INTERNAL;
8441                 goto EXIT;
8442         }
8443
8444         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8445         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8446
8447         caps = gst_pad_get_current_caps(sinkpad);
8448         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8449
8450         if (sinkpad)
8451                 gst_object_unref(sinkpad);
8452
8453         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8454                 _mmplayer_set_audio_attrs(player, caps);
8455
8456         if (caps)
8457                 gst_caps_unref(caps);
8458
8459 EXIT:
8460         MMPLAYER_FREEIF(change_pad_name);
8461         return result;
8462 }
8463
8464 int
8465 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8466 {
8467         int result = MM_ERROR_NONE;
8468         mmplayer_t *player = NULL;
8469         mmplayer_gst_element_t *mainbin = NULL;
8470
8471         gint current_active_index = 0;
8472
8473         GstState current_state = GST_STATE_VOID_PENDING;
8474         gint64 time = 0;
8475
8476         MMPLAYER_FENTER();
8477
8478         player = (mmplayer_t *)hplayer;
8479         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8480
8481         if (!player->pipeline) {
8482                 LOGE("Track %d pre setting -> %d", type, index);
8483
8484                 player->track[type].active_track_index = index;
8485                 goto EXIT;
8486         }
8487
8488         mainbin = player->pipeline->mainbin;
8489
8490         current_active_index = player->track[type].active_track_index;
8491
8492         /*If index is same as running index no need to change the pad*/
8493         if (current_active_index == index)
8494                 goto EXIT;
8495
8496         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8497                 result = MM_ERROR_PLAYER_INVALID_STATE;
8498                 goto EXIT;
8499         }
8500
8501         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8502         if (current_state < GST_STATE_PAUSED) {
8503                 result = MM_ERROR_PLAYER_INVALID_STATE;
8504                 LOGW("Pipeline not in proper state");
8505                 goto EXIT;
8506         }
8507
8508         if (MMPLAYER_USE_DECODEBIN(player))
8509                 result = __mmplayer_change_selector_pad(player, type, index);
8510         else
8511                 result = __mmplayer_switch_stream(player, type, index);
8512
8513         if (result != MM_ERROR_NONE) {
8514                 LOGE("failed to change track");
8515                 goto EXIT;
8516         }
8517
8518         player->track[type].active_track_index = index;
8519
8520         if (MMPLAYER_USE_DECODEBIN(player)) {
8521                 GstEvent *event = NULL;
8522                 if (current_state == GST_STATE_PLAYING) {
8523                         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8524                                 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8525                                 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8526                         if (event) {
8527                                 _mmplayer_gst_send_event_to_sink(player, event);
8528                         } else {
8529                                 result = MM_ERROR_PLAYER_INTERNAL;
8530                                 goto EXIT;
8531                         }
8532                 }
8533         }
8534
8535 EXIT:
8536         return result;
8537 }
8538
8539 int
8540 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8541 {
8542         mmplayer_t *player = (mmplayer_t *)hplayer;
8543
8544         MMPLAYER_FENTER();
8545
8546         /* check player handle */
8547         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8548
8549         *silent = player->set_mode.subtitle_off;
8550
8551         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8552
8553         MMPLAYER_FLEAVE();
8554
8555         return MM_ERROR_NONE;
8556 }
8557
8558 static gboolean
8559 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8560 {
8561         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8562         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8563
8564         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8565         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8566
8567         int idx = 0;
8568
8569         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8570                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8571                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8572                         mmplayer_dump_t *dump_s;
8573                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8574                         if (dump_s == NULL) {
8575                                 LOGE("malloc fail");
8576                                 return FALSE;
8577                         }
8578
8579                         dump_s->dump_element_file = NULL;
8580                         dump_s->dump_pad = NULL;
8581                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8582
8583                         if (dump_s->dump_pad) {
8584                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8585                                 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]);
8586                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8587                                 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);
8588                                 /* add list for removed buffer probe and close FILE */
8589                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8590                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8591                                 return TRUE;
8592                         } else {
8593                                 MMPLAYER_FREEIF(dump_s);
8594                                 LOGE("failed to get %s sink pad added", factory_name);
8595                         }
8596                 }
8597         }
8598         return FALSE;
8599 }
8600
8601 static GstPadProbeReturn
8602 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8603 {
8604         FILE *dump_data = (FILE *)u_data;
8605 //      int written = 0;
8606         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8607         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8608
8609         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8610
8611         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8612 #ifdef __DEBUG__
8613         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8614 #endif
8615         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8616
8617         gst_buffer_unmap(buffer, &probe_info);
8618
8619         return GST_PAD_PROBE_OK;
8620 }
8621
8622 static void
8623 __mmplayer_release_dump_list(GList *dump_list)
8624 {
8625         GList *d_list = dump_list;
8626
8627         if (!d_list)
8628                 return;
8629
8630         for (; d_list; d_list = g_list_next(d_list)) {
8631                 mmplayer_dump_t *dump_s = d_list->data;
8632                 if (dump_s->dump_pad) {
8633                         if (dump_s->probe_handle_id)
8634                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8635                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8636                 }
8637                 if (dump_s->dump_element_file) {
8638                         fclose(dump_s->dump_element_file);
8639                         dump_s->dump_element_file = NULL;
8640                 }
8641                 MMPLAYER_FREEIF(dump_s);
8642         }
8643         g_list_free(dump_list);
8644         dump_list = NULL;
8645 }
8646
8647 int
8648 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8649 {
8650         mmplayer_t *player = (mmplayer_t *)hplayer;
8651
8652         MMPLAYER_FENTER();
8653
8654         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8655         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8656
8657         *exist = (bool)player->has_closed_caption;
8658
8659         MMPLAYER_FLEAVE();
8660
8661         return MM_ERROR_NONE;
8662 }
8663
8664 void
8665 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8666 {
8667         MMPLAYER_FENTER();
8668         if (buffer) {
8669 #ifdef __DEBUG__
8670                 LOGD("unref internal gst buffer %p", buffer);
8671 #endif
8672                 gst_buffer_unref((GstBuffer *)buffer);
8673                 buffer = NULL;
8674         }
8675         MMPLAYER_FLEAVE();
8676 }
8677
8678 int
8679 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8680 {
8681         mmplayer_t *player = (mmplayer_t *)hplayer;
8682
8683         MMPLAYER_FENTER();
8684
8685         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8686         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8687
8688         if (MMPLAYER_IS_STREAMING(player))
8689                 *timeout = (int)player->ini.live_state_change_timeout;
8690         else
8691                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8692
8693         LOGD("timeout = %d", *timeout);
8694
8695         MMPLAYER_FLEAVE();
8696         return MM_ERROR_NONE;
8697 }
8698
8699 static void
8700 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8701 {
8702         int i = 0;
8703         MMPLAYER_FENTER();
8704         MMPLAYER_RETURN_IF_FAIL(player);
8705
8706         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8707
8708                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8709                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8710                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8711                         player->storage_info[i].id = -1;
8712                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8713
8714                         if (path_type != MMPLAYER_PATH_MAX)
8715                                 break;
8716                 }
8717         }
8718
8719         MMPLAYER_FLEAVE();
8720 }
8721
8722 int
8723 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8724 {
8725         int ret = MM_ERROR_NONE;
8726         mmplayer_t *player = (mmplayer_t *)hplayer;
8727         MMMessageParamType msg_param = {0, };
8728
8729         MMPLAYER_FENTER();
8730         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731
8732         LOGW("state changed storage %d:%d", id, state);
8733
8734         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8735                 return MM_ERROR_NONE;
8736
8737         /* FIXME: text path should be handled separately. */
8738         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8739                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8740                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8741                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8742                 LOGW("external storage is removed");
8743
8744                 if (player->msg_posted == FALSE) {
8745                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8746                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8747                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8748                         player->msg_posted = TRUE;
8749                 }
8750
8751                 /* unrealize the player */
8752                 ret = _mmplayer_unrealize(hplayer);
8753                 if (ret != MM_ERROR_NONE)
8754                         LOGE("failed to unrealize");
8755         }
8756
8757         MMPLAYER_FLEAVE();
8758         return ret;
8759 }
8760
8761 int
8762 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8763 {
8764         int ret = MM_ERROR_NONE;
8765         mmplayer_t *player = (mmplayer_t *)hplayer;
8766         int idx = 0, total = 0;
8767         gchar *result = NULL, *tmp = NULL;
8768
8769         MMPLAYER_FENTER();
8770         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8771         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8772
8773         total = *num = g_list_length(player->adaptive_info.var_list);
8774         if (total <= 0) {
8775                 LOGW("There is no stream variant info.");
8776                 return ret;
8777         }
8778
8779         result = g_strdup("");
8780         for (idx = 0 ; idx < total ; idx++) {
8781                 stream_variant_t *v_data = NULL;
8782                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8783
8784                 if (v_data) {
8785                         gchar data[64] = {0};
8786                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8787
8788                         tmp = g_strconcat(result, data, NULL);
8789                         g_free(result);
8790                         result = tmp;
8791                 } else {
8792                         LOGW("There is no variant data in %d", idx);
8793                         (*num)--;
8794                 }
8795         }
8796
8797         *var_info = (char *)result;
8798
8799         LOGD("variant info %d:%s", *num, *var_info);
8800         MMPLAYER_FLEAVE();
8801         return ret;
8802 }
8803
8804 int
8805 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8806 {
8807         int ret = MM_ERROR_NONE;
8808         mmplayer_t *player = (mmplayer_t *)hplayer;
8809
8810         MMPLAYER_FENTER();
8811         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812
8813         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8814
8815         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8816         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8817         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8818
8819         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8820                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8821                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8822                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8823
8824                 /* FIXME: seek to current position for applying new variant limitation */
8825         }
8826
8827         MMPLAYER_FLEAVE();
8828         return ret;
8829
8830 }
8831
8832 int
8833 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8834 {
8835         int ret = MM_ERROR_NONE;
8836         mmplayer_t *player = (mmplayer_t *)hplayer;
8837
8838         MMPLAYER_FENTER();
8839         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8840         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8841
8842         *bandwidth = player->adaptive_info.limit.bandwidth;
8843         *width = player->adaptive_info.limit.width;
8844         *height = player->adaptive_info.limit.height;
8845
8846         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8847
8848         MMPLAYER_FLEAVE();
8849         return ret;
8850 }
8851
8852 int
8853 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8854 {
8855         int ret = MM_ERROR_NONE;
8856         mmplayer_t *player = (mmplayer_t *)hplayer;
8857
8858         MMPLAYER_FENTER();
8859         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8860         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8861         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8862
8863         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8864
8865         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8866                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8867         else /* live case */
8868                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8869
8870         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8871
8872         MMPLAYER_FLEAVE();
8873         return ret;
8874 }
8875
8876 int
8877 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8878 {
8879 #define IDX_FIRST_SW_CODEC 0
8880         mmplayer_t *player = (mmplayer_t *)hplayer;
8881         int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8882         const char *attr_name = NULL;
8883         const char *default_type = NULL;
8884         const char *element_hw = NULL;
8885         const char *element_sw = NULL;
8886
8887         MMPLAYER_FENTER();
8888         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8889
8890         LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8891
8892         /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8893         switch (stream_type) {
8894         case MM_PLAYER_STREAM_TYPE_AUDIO:
8895                 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8896                 default_type = player->ini.audiocodec_default_type;
8897                 element_hw = player->ini.audiocodec_element_hw;
8898                 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8899                 break;
8900         case MM_PLAYER_STREAM_TYPE_VIDEO:
8901                 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8902                 default_type = player->ini.videocodec_default_type;
8903                 element_hw = player->ini.videocodec_element_hw;
8904                 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8905                 break;
8906         default:
8907                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8908                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8909                 break;
8910         }
8911
8912         LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8913
8914         if (!strcmp(default_type, "sw"))
8915                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8916         else
8917                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8918
8919         if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8920                 codec_type = default_codec_type;
8921
8922         /* to support codec selection, codec info have to be added in ini file.
8923            in case of hw codec is selected, filter elements should be applied
8924            depending on the hw capabilities. */
8925         if (codec_type != default_codec_type) {
8926                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8927                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8928                         LOGE("There is no codec for type %d", codec_type);
8929                         return MM_ERROR_PLAYER_NO_OP;
8930                 }
8931
8932                 LOGD("sorting is required");
8933                 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8934                         player->need_audio_dec_sorting = TRUE;
8935                 else
8936                         player->need_video_dec_sorting = TRUE;
8937         }
8938
8939         LOGD("update %s codec_type to %d", attr_name, codec_type);
8940         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8941
8942         MMPLAYER_FLEAVE();
8943         return MM_ERROR_NONE;
8944 }
8945
8946 int
8947 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8948 {
8949         mmplayer_t *player = (mmplayer_t *)hplayer;
8950         GstElement *rg_vol_element = NULL;
8951
8952         MMPLAYER_FENTER();
8953
8954         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8955
8956         player->sound.rg_enable = enabled;
8957
8958         /* just hold rgvolume enable value if pipeline is not ready */
8959         if (!player->pipeline || !player->pipeline->audiobin) {
8960                 LOGD("pipeline is not ready. holding rgvolume enable value");
8961                 return MM_ERROR_NONE;
8962         }
8963
8964         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8965
8966         if (!rg_vol_element) {
8967                 LOGD("rgvolume element is not created");
8968                 return MM_ERROR_PLAYER_INTERNAL;
8969         }
8970
8971         if (enabled)
8972                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8973         else
8974                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8975
8976         MMPLAYER_FLEAVE();
8977
8978         return MM_ERROR_NONE;
8979 }
8980
8981 int
8982 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8983 {
8984         mmplayer_t *player = (mmplayer_t *)hplayer;
8985         GstElement *rg_vol_element = NULL;
8986         gboolean enable = FALSE;
8987
8988         MMPLAYER_FENTER();
8989
8990         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8991         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8992
8993         /* just hold enable_rg value if pipeline is not ready */
8994         if (!player->pipeline || !player->pipeline->audiobin) {
8995                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8996                 *enabled = player->sound.rg_enable;
8997                 return MM_ERROR_NONE;
8998         }
8999
9000         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9001
9002         if (!rg_vol_element) {
9003                 LOGD("rgvolume element is not created");
9004                 return MM_ERROR_PLAYER_INTERNAL;
9005         }
9006
9007         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9008         *enabled = (bool)enable;
9009
9010         MMPLAYER_FLEAVE();
9011
9012         return MM_ERROR_NONE;
9013 }
9014
9015 int
9016 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9017 {
9018         mmplayer_t *player = (mmplayer_t *)hplayer;
9019         MMHandleType attrs = 0;
9020         int handle = 0;
9021         int ret = MM_ERROR_NONE;
9022
9023         MMPLAYER_FENTER();
9024
9025         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9026
9027         attrs = MMPLAYER_GET_ATTRS(player);
9028         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9029
9030         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9031         if (!handle) {
9032                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9033                 return MM_ERROR_PLAYER_INTERNAL;
9034         }
9035
9036         player->video_roi.scale_x = scale_x;
9037         player->video_roi.scale_y = scale_y;
9038         player->video_roi.scale_width = scale_width;
9039         player->video_roi.scale_height = scale_height;
9040
9041         /* check video sinkbin is created */
9042         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9043                 return MM_ERROR_NONE;
9044
9045         if (!gst_video_overlay_set_video_roi_area(
9046                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9047                 scale_x, scale_y, scale_width, scale_height))
9048                 ret = MM_ERROR_PLAYER_INTERNAL;
9049         else
9050                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9051                         scale_x, scale_y, scale_width, scale_height);
9052
9053         MMPLAYER_FLEAVE();
9054
9055         return ret;
9056 }
9057
9058 int
9059 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9060 {
9061         mmplayer_t *player = (mmplayer_t *)hplayer;
9062         int ret = MM_ERROR_NONE;
9063
9064         MMPLAYER_FENTER();
9065
9066         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9067         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9068
9069         *scale_x = player->video_roi.scale_x;
9070         *scale_y = player->video_roi.scale_y;
9071         *scale_width = player->video_roi.scale_width;
9072         *scale_height = player->video_roi.scale_height;
9073
9074         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9075                 *scale_x, *scale_y, *scale_width, *scale_height);
9076
9077         return ret;
9078 }
9079
9080 int
9081 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9082 {
9083         mmplayer_t *player = (mmplayer_t *)hplayer;
9084
9085         MMPLAYER_FENTER();
9086
9087         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9088
9089         player->client_pid = pid;
9090
9091         LOGD("client pid[%d] %p", pid, player);
9092
9093         MMPLAYER_FLEAVE();
9094
9095         return MM_ERROR_NONE;
9096 }
9097
9098 int
9099 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9100 {
9101         mmplayer_t *player = (mmplayer_t *)hplayer;
9102         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9103         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9104
9105         MMPLAYER_FENTER();
9106
9107         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9108         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9109
9110         *available = true;
9111         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9112
9113         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9114
9115         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9116                 return MM_ERROR_NONE;
9117
9118         /* in case of audio codec default type is HW */
9119         switch(opt) {
9120                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9121                         if (player->ini.support_audio_effect)
9122                                 return MM_ERROR_NONE;
9123                         elem_id = MMPLAYER_A_FILTER;
9124                 break;
9125                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9126                         if (player->ini.support_replaygain_control)
9127                                 return MM_ERROR_NONE;
9128                         elem_id = MMPLAYER_A_RGVOL;
9129                 break;
9130                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9131                         if (player->ini.support_pitch_control)
9132                                 return MM_ERROR_NONE;
9133                         elem_id = MMPLAYER_A_PITCH;
9134                 break;
9135                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9136                         if (player->ini.support_audio_effect)
9137                                 return MM_ERROR_NONE;
9138                 break;
9139                 /* default case handling is not required */
9140         }
9141
9142         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9143                 LOGW("audio control option [%d] is not available", opt);
9144                 *available = false;
9145         } else {
9146                 /* setting pcm exporting option is allowed before READY state */
9147                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9148                         return MM_ERROR_PLAYER_INVALID_STATE;
9149
9150                 /* check whether the audio filter exist or not after READY state,
9151                    because the sw codec could be added during auto-plugging in some cases */
9152                 if (!player->pipeline ||
9153                         !player->pipeline->audiobin ||
9154                         !player->pipeline->audiobin[elem_id].gst) {
9155                         LOGW("there is no audio elem [%d]", elem_id);
9156                         *available = false;
9157                 }
9158         }
9159
9160         LOGD("audio control opt %d, available %d", opt, *available);
9161
9162         MMPLAYER_FLEAVE();
9163
9164         return MM_ERROR_NONE;
9165 }
9166
9167 static gboolean
9168 __mmplayer_update_duration_value(mmplayer_t *player)
9169 {
9170         gboolean ret = FALSE;
9171         gint64 dur_nsec = 0;
9172         LOGD("try to update duration");
9173
9174         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9175                 player->duration = dur_nsec;
9176                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9177                 ret = TRUE;
9178         }
9179
9180         if (player->duration < 0) {
9181                 LOGW("duration is Non-Initialized !!!");
9182                 player->duration = 0;
9183         }
9184
9185         /* update streaming service type */
9186         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9187
9188         /* check duration is OK */
9189         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9190                 /* FIXIT : find another way to get duration here. */
9191                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9192
9193         return ret;
9194 }
9195
9196 static gboolean
9197 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9198 {
9199         /* update audio params
9200         NOTE : We need original audio params and it can be only obtained from src pad of audio
9201         decoder. Below code only valid when we are not using 'resampler' just before
9202         'audioconverter'. */
9203         GstCaps *caps_a = NULL;
9204         GstPad *pad = NULL;
9205         gint samplerate = 0, channels = 0;
9206         GstStructure *p = NULL;
9207         GstElement *aconv = NULL;
9208
9209         LOGD("try to update audio attrs");
9210
9211         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9212
9213         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9214                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9215         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9216                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9217         } else {
9218                 LOGE("there is no audio converter");
9219                 return FALSE;
9220         }
9221
9222         pad = gst_element_get_static_pad(aconv, "sink");
9223
9224         if (!pad) {
9225                 LOGW("failed to get pad from audio converter");
9226                 return FALSE;
9227         }
9228
9229         caps_a = gst_pad_get_current_caps(pad);
9230         if (!caps_a) {
9231                 LOGW("not ready to get audio caps");
9232                 gst_object_unref(pad);
9233                 return FALSE;
9234         }
9235
9236         p = gst_caps_get_structure(caps_a, 0);
9237
9238         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9239
9240         gst_structure_get_int(p, "rate", &samplerate);
9241         gst_structure_get_int(p, "channels", &channels);
9242
9243         mm_player_set_attribute((MMHandleType)player, NULL,
9244                         "content_audio_samplerate", samplerate,
9245                         "content_audio_channels", channels, NULL);
9246
9247         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9248
9249         gst_caps_unref(caps_a);
9250         gst_object_unref(pad);
9251
9252         return TRUE;
9253 }
9254
9255 static gboolean
9256 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9257 {
9258         LOGD("try to update video attrs");
9259
9260         GstCaps *caps_v = NULL;
9261         GstPad *pad = NULL;
9262         gint tmpNu, tmpDe;
9263         gint width, height;
9264         GstStructure *p = NULL;
9265
9266         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9267         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9268
9269         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9270         if (!pad) {
9271                 LOGD("no videosink sink pad");
9272                 return FALSE;
9273         }
9274
9275         caps_v = gst_pad_get_current_caps(pad);
9276         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9277         if (!caps_v && player->v_stream_caps) {
9278                 caps_v = player->v_stream_caps;
9279                 gst_caps_ref(caps_v);
9280         }
9281
9282         if (!caps_v) {
9283                 LOGD("no negotiated caps from videosink");
9284                 gst_object_unref(pad);
9285                 return FALSE;
9286         }
9287
9288         p = gst_caps_get_structure(caps_v, 0);
9289         gst_structure_get_int(p, "width", &width);
9290         gst_structure_get_int(p, "height", &height);
9291
9292         mm_player_set_attribute((MMHandleType)player, NULL,
9293                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9294
9295         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9296
9297         SECURE_LOGD("width : %d     height : %d", width, height);
9298
9299         gst_caps_unref(caps_v);
9300         gst_object_unref(pad);
9301
9302         if (tmpDe > 0) {
9303                 mm_player_set_attribute((MMHandleType)player, NULL,
9304                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9305                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9306         }
9307
9308         return TRUE;
9309 }
9310
9311 static gboolean
9312 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9313 {
9314         gboolean ret = FALSE;
9315         guint64 data_size = 0;
9316         gchar *path = NULL;
9317         struct stat sb;
9318
9319         /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9320         if (!player->duration)
9321                 return FALSE;
9322
9323         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9324                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9325                 if (stat(path, &sb) == 0)
9326                         data_size = (guint64)sb.st_size;
9327
9328         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9329                 data_size = player->http_content_size;
9330         }
9331
9332         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9333
9334         if (data_size) {
9335                 guint64 bitrate = 0;
9336                 guint64 msec_dur = 0;
9337
9338                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9339                 if (msec_dur > 0) {
9340                         bitrate = data_size * 8 * 1000 / msec_dur;
9341                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9342                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9343                         mm_player_set_attribute((MMHandleType)player, NULL,
9344                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9345                         ret = TRUE;
9346                 } else {
9347                         LOGD("player duration is less than 0");
9348                 }
9349         }
9350
9351         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9352                 if (player->total_bitrate) {
9353                         mm_player_set_attribute((MMHandleType)player, NULL,
9354                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9355                         ret = TRUE;
9356                 }
9357         }
9358
9359         return ret;
9360 }
9361
9362 static void
9363 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9364 {
9365         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9366         data->uri_type = uri_type;
9367 }
9368
9369 static int
9370 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9371 {
9372         int ret = MM_ERROR_PLAYER_INVALID_URI;
9373         int mem_size = 0;
9374         char *buffer = NULL;
9375         char *seperator = strchr(path, ',');
9376         char ext[100] = {0,}, size[100] = {0,};
9377
9378         if (seperator) {
9379                 if ((buffer = strstr(path, "ext="))) {
9380                         buffer += strlen("ext=");
9381
9382                         if (strlen(buffer)) {
9383                                 strncpy(ext, buffer, 99);
9384
9385                                 if ((seperator = strchr(ext, ','))
9386                                         || (seperator = strchr(ext, ' '))
9387                                         || (seperator = strchr(ext, '\0'))) {
9388                                         seperator[0] = '\0';
9389                                 }
9390                         }
9391                 }
9392
9393                 if ((buffer = strstr(path, "size="))) {
9394                         buffer += strlen("size=");
9395
9396                         if (strlen(buffer) > 0) {
9397                                 strncpy(size, buffer, 99);
9398
9399                                 if ((seperator = strchr(size, ','))
9400                                         || (seperator = strchr(size, ' '))
9401                                         || (seperator = strchr(size, '\0'))) {
9402                                         seperator[0] = '\0';
9403                                 }
9404
9405                                 mem_size = atoi(size);
9406                         }
9407                 }
9408         }
9409
9410         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9411
9412         if (mem_size && param) {
9413                 if (data->input_mem.buf)
9414                         free(data->input_mem.buf);
9415                 data->input_mem.buf = malloc(mem_size);
9416
9417                 if (data->input_mem.buf) {
9418                         memcpy(data->input_mem.buf, param, mem_size);
9419                         data->input_mem.len = mem_size;
9420                         ret = MM_ERROR_NONE;
9421                 } else {
9422                         LOGE("failed to alloc mem %d", mem_size);
9423                         ret = MM_ERROR_PLAYER_INTERNAL;
9424                 }
9425
9426                 data->input_mem.offset = 0;
9427                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9428         }
9429
9430         return ret;
9431 }
9432
9433 static int
9434 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9435 {
9436         gchar *location = NULL;
9437         GError *err = NULL;
9438         char *path = NULL;
9439         int ret = MM_ERROR_NONE;
9440
9441         if ((path = strstr(uri, "file://"))) {
9442                 location = g_filename_from_uri(uri, NULL, &err);
9443                 if (!location || (err != NULL)) {
9444                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9445                                 (err != NULL) ? err->message : "unknown error");
9446                         if (err)
9447                                 g_error_free(err);
9448
9449                         MMPLAYER_FREEIF(location);
9450
9451                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9452                         return MM_ERROR_PLAYER_INVALID_URI;
9453                 }
9454                 LOGD("path from uri: %s", location);
9455         }
9456
9457         path = (location != NULL) ? (location) : ((char *)uri);
9458
9459
9460         ret = _mmplayer_exist_file_path(path);
9461
9462         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9463         if (ret == MM_ERROR_NONE) {
9464                 if (_mmplayer_is_sdp_file(path)) {
9465                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9466                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9467                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9468                 } else {
9469                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9470                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9471                 }
9472         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9473                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9474         } else {
9475                 LOGE("invalid uri, could not play..");
9476                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9477         }
9478
9479         MMPLAYER_FREEIF(location);
9480
9481         return ret;
9482 }
9483
9484 static mmplayer_video_decoded_data_info_t *
9485 __mmplayer_create_stream_from_pad(GstPad *pad)
9486 {
9487         GstCaps *caps = NULL;
9488         GstStructure *structure = NULL;
9489         unsigned int fourcc = 0;
9490         const gchar *string_format = NULL;
9491         mmplayer_video_decoded_data_info_t *stream = NULL;
9492         gint width, height;
9493         MMPixelFormatType format;
9494         GstVideoInfo info;
9495
9496         caps = gst_pad_get_current_caps(pad);
9497         if (!caps) {
9498                 LOGE("Caps is NULL.");
9499                 return NULL;
9500         }
9501
9502 #ifdef __DEBUG__
9503         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9504 #endif
9505         structure = gst_caps_get_structure(caps, 0);
9506         gst_structure_get_int(structure, "width", &width);
9507         gst_structure_get_int(structure, "height", &height);
9508         string_format = gst_structure_get_string(structure, "format");
9509
9510         if (string_format)
9511                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9512         format = _mmplayer_get_pixtype(fourcc);
9513         gst_video_info_from_caps(&info, caps);
9514         gst_caps_unref(caps);
9515
9516         /* moved here */
9517         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9518                 LOGE("Wrong condition!!");
9519                 return NULL;
9520         }
9521
9522         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9523         if (!stream) {
9524                 LOGE("failed to alloc mem for video data");
9525                 return NULL;
9526         }
9527
9528         stream->width = width;
9529         stream->height = height;
9530         stream->format = format;
9531         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9532
9533         return stream;
9534 }
9535
9536 static void
9537 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9538 {
9539         unsigned int pitch = 0;
9540         unsigned int size = 0;
9541         int index = 0;
9542         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9543         tbm_bo bo = NULL;
9544
9545         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9546                 bo = gst_tizen_memory_get_bos(mem, index);
9547                 if (bo)
9548                         stream->bo[index] = tbm_bo_ref(bo);
9549                 else
9550                         LOGE("failed to get bo for index %d", index);
9551         }
9552
9553         for (index = 0; index < stream->plane_num; index++) {
9554                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9555                 stream->stride[index] = pitch;
9556                 if (pitch)
9557                         stream->elevation[index] = size / pitch;
9558                 else
9559                         stream->elevation[index] = stream->height;
9560         }
9561 }
9562
9563 static gboolean
9564 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9565 {
9566         if (stream->format == MM_PIXEL_FORMAT_I420) {
9567                 int ret = TBM_SURFACE_ERROR_NONE;
9568                 tbm_surface_h surface;
9569                 tbm_surface_info_s info;
9570
9571                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9572
9573                 ret = tbm_surface_get_info(surface, &info);
9574                 if (ret != TBM_SURFACE_ERROR_NONE) {
9575                         tbm_surface_destroy(surface);
9576                         return FALSE;
9577                 }
9578
9579                 tbm_surface_destroy(surface);
9580                 stream->stride[0] = info.planes[0].stride;
9581                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9582                 stream->stride[1] = info.planes[1].stride;
9583                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9584                 stream->stride[2] = info.planes[2].stride;
9585                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9586                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9587         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9588                 stream->stride[0] = stream->width * 4;
9589                 stream->elevation[0] = stream->height;
9590                 stream->bo_size = stream->stride[0] * stream->height;
9591         } else {
9592                 LOGE("Not support format %d", stream->format);
9593                 return FALSE;
9594         }
9595
9596         return TRUE;
9597 }
9598
9599 static gboolean
9600 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9601 {
9602         tbm_bo_handle thandle;
9603         gboolean is_mapped;
9604         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9605         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9606         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9607         int i = 0;
9608         int j = 0;
9609         int k = 0;
9610         unsigned char *src = NULL;
9611         unsigned char *dest = NULL;
9612         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9613
9614         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9615         if (!is_mapped) {
9616                 LOGE("fail to gst_memory_map");
9617                 return FALSE;
9618         }
9619
9620         if (!mapinfo.data) {
9621                 LOGE("data pointer is wrong");
9622                 goto ERROR;
9623         }
9624
9625         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9626         if (!stream->bo[0]) {
9627                 LOGE("Fail to tbm_bo_alloc!!");
9628                 goto ERROR;
9629         }
9630
9631         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9632         if (!thandle.ptr) {
9633                 LOGE("thandle pointer is wrong");
9634                 goto ERROR;
9635         }
9636
9637         if (stream->format == MM_PIXEL_FORMAT_I420) {
9638                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9639                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9640                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9641                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9642
9643                 dest_offset[0] = 0;
9644                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9645                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9646
9647                 for (i = 0; i < 3; i++) {
9648                         src = mapinfo.data + src_offset[i];
9649                         dest = thandle.ptr + dest_offset[i];
9650
9651                         if (i > 0)
9652                                 k = 1;
9653
9654                         for (j = 0; j < stream->height >> k; j++) {
9655                                 memcpy(dest, src, stream->width>>k);
9656                                 src += src_stride[i];
9657                                 dest += stream->stride[i];
9658                         }
9659                 }
9660         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9661                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9662         } else {
9663                 LOGE("Not support format %d", stream->format);
9664                 goto ERROR;
9665         }
9666
9667         tbm_bo_unmap(stream->bo[0]);
9668         gst_memory_unmap(mem, &mapinfo);
9669
9670         return TRUE;
9671
9672 ERROR:
9673         if (stream->bo[0])
9674                 tbm_bo_unmap(stream->bo[0]);
9675
9676         if (is_mapped)
9677                 gst_memory_unmap(mem, &mapinfo);
9678
9679         return FALSE;
9680 }
9681
9682 static void
9683 __mmplayer_set_pause_state(mmplayer_t *player)
9684 {
9685         if (player->sent_bos)
9686                 return;
9687
9688         /* rtsp case, get content attrs by GstMessage */
9689         if (MMPLAYER_IS_RTSP_STREAMING(player))
9690                 return;
9691
9692         /* it's first time to update all content attrs. */
9693         _mmplayer_update_content_attrs(player, ATTR_ALL);
9694 }
9695
9696 static void
9697 __mmplayer_set_playing_state(mmplayer_t *player)
9698 {
9699         gchar *audio_codec = NULL;
9700
9701         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9702                 /* initialize because auto resume is done well. */
9703                 player->resumed_by_rewind = FALSE;
9704                 player->playback_rate = 1.0;
9705         }
9706
9707         if (player->sent_bos)
9708                 return;
9709
9710         /* try to get content metadata */
9711
9712         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9713          * c-api since c-api doesn't use _start() anymore. It may not work properly with
9714          * legacy mmfw-player api
9715          */
9716         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9717
9718         if ((player->cmd == MMPLAYER_COMMAND_START)
9719                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9720                 __mmplayer_handle_missed_plugin(player);
9721         }
9722
9723         /* check audio codec field is set or not
9724          * we can get it from typefinder or codec's caps.
9725          */
9726         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9727
9728         /* The codec format can't be sent for audio only case like amr, mid etc.
9729          * Because, parser don't make related TAG.
9730          * So, if it's not set yet, fill it with found data.
9731          */
9732         if (!audio_codec) {
9733                 if (g_strrstr(player->type, "audio/midi"))
9734                         audio_codec = "MIDI";
9735                 else if (g_strrstr(player->type, "audio/x-amr"))
9736                         audio_codec = "AMR";
9737                 else if (g_strrstr(player->type, "audio/mpeg")
9738                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9739                         audio_codec = "AAC";
9740                 else
9741                         audio_codec = "unknown";
9742
9743                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9744                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9745                         LOGE("failed to set attribute");
9746
9747                 LOGD("set audio codec type with caps");
9748         }
9749
9750         return;
9751 }