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