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