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