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