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