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