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