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