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