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