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