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