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