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