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