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