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         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3457                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3458
3459                 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3460                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3461                                 "use-tbm", use_tbm, NULL);
3462                 }
3463                 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3464                         return MM_ERROR_PLAYER_INTERNAL;
3465
3466         } else {
3467                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3468                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3469         }
3470         LOGD("surface type : %d, videosink factory name is %s use-tbm : %d", surface_type, factory_name, use_tbm);
3471
3472         mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3473         if (gapless > 0) {
3474                 LOGD("disable last-sample");
3475                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3476         }
3477
3478         if (player->set_mode.video_export) {
3479                 int enable = 0;
3480                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3481                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3482                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3483
3484                 _mmplayer_add_signal_connection(player,
3485                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3486                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3487                                                                 "handoff",
3488                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3489                                                                 (gpointer)player);
3490
3491                 _mmplayer_add_signal_connection(player,
3492                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3493                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3494                                                                 "preroll-handoff",
3495                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3496                                                                 (gpointer)player);
3497         }
3498
3499         if (videobin[MMPLAYER_V_SINK].gst) {
3500                 GstPad *sink_pad = NULL;
3501                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3502                 if (sink_pad) {
3503                         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3504                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3505                         gst_object_unref(GST_OBJECT(sink_pad));
3506                 } else {
3507                         LOGE("failed to get sink pad from videosink");
3508                 }
3509         }
3510
3511         return MM_ERROR_NONE;
3512 }
3513
3514 /**
3515  * VIDEO BIN
3516  * - video overlay surface(arm/x86) : tizenwlsink
3517  */
3518 static int
3519 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3520 {
3521         GstPad *pad = NULL;
3522         GList *element_bucket = NULL;
3523         mmplayer_gst_element_t *first_element = NULL;
3524         mmplayer_gst_element_t *videobin = NULL;
3525         gchar *videosink_factory_name = NULL;
3526
3527         MMPLAYER_FENTER();
3528         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3529
3530         /* alloc handles */
3531         videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3532         if (!videobin)
3533                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3534
3535         player->pipeline->videobin = videobin;
3536
3537         /* create bin */
3538         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3539         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3540         if (!videobin[MMPLAYER_V_BIN].gst) {
3541                 LOGE("failed to create videobin");
3542                 goto ERROR;
3543         }
3544
3545         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3546                 goto ERROR;
3547
3548         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3549         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3550
3551         /* additional setting for sink plug-in */
3552         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3553                 LOGE("failed to set video property");
3554                 goto ERROR;
3555         }
3556
3557         /* store it as it's sink element */
3558         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3559
3560         /* adding created elements to bin */
3561         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3562                 LOGE("failed to add elements");
3563                 goto ERROR;
3564         }
3565
3566         /* Linking elements in the bucket by added order */
3567         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3568                 LOGE("failed to link elements");
3569                 goto ERROR;
3570         }
3571
3572         /* get first element's sinkpad for creating ghostpad */
3573         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3574         if (!first_element) {
3575                 LOGE("failed to get first element from bucket");
3576                 goto ERROR;
3577         }
3578
3579         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3580         if (!pad) {
3581                 LOGE("failed to get pad from first element");
3582                 goto ERROR;
3583         }
3584
3585         /* create ghostpad */
3586         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3587         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3588                 LOGE("failed to add ghostpad to videobin");
3589                 goto ERROR;
3590         }
3591         gst_object_unref(pad);
3592
3593         /* done. free allocated variables */
3594         g_list_free(element_bucket);
3595
3596         MMPLAYER_FLEAVE();
3597
3598         return MM_ERROR_NONE;
3599
3600 ERROR:
3601         LOGE("ERROR : releasing videobin");
3602         g_list_free(element_bucket);
3603
3604         if (pad)
3605                 gst_object_unref(GST_OBJECT(pad));
3606
3607         /* release videobin with it's childs */
3608         if (videobin[MMPLAYER_V_BIN].gst)
3609                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3610
3611         MMPLAYER_FREEIF(videobin);
3612         player->pipeline->videobin = NULL;
3613
3614         return MM_ERROR_PLAYER_INTERNAL;
3615 }
3616
3617 static int
3618 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3619 {
3620         GList *element_bucket = NULL;
3621         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3622
3623         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3624         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3625         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3626                                                         "signal-handoffs", FALSE,
3627                                                         NULL);
3628
3629         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3630         _mmplayer_add_signal_connection(player,
3631                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3632                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3633                                                         "handoff",
3634                                                         G_CALLBACK(__mmplayer_update_subtitle),
3635                                                         (gpointer)player);
3636
3637         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3638                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3639
3640         if (!player->play_subtitle) {
3641                 LOGD("add textbin sink as sink element of whole pipeline.");
3642                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3643         }
3644
3645         /* adding created elements to bin */
3646         LOGD("adding created elements to bin");
3647         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3648                 LOGE("failed to add elements");
3649                 goto ERROR;
3650         }
3651
3652         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3653         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3654         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3655
3656         /* linking elements in the bucket by added order. */
3657         LOGD("Linking elements in the bucket by added order.");
3658         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3659                 LOGE("failed to link elements");
3660                 goto ERROR;
3661         }
3662
3663         /* done. free allocated variables */
3664         g_list_free(element_bucket);
3665
3666         if (textbin[MMPLAYER_T_QUEUE].gst) {
3667                 GstPad *pad = NULL;
3668                 GstPad *ghostpad = NULL;
3669
3670                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3671                 if (!pad) {
3672                         LOGE("failed to get sink pad of text queue");
3673                         goto ERROR;
3674                 }
3675
3676                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3677                 gst_object_unref(pad);
3678
3679                 if (!ghostpad) {
3680                         LOGE("failed to create ghostpad of textbin");
3681                         goto ERROR;
3682                 }
3683
3684                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3685                         LOGE("failed to add ghostpad to textbin");
3686                         gst_object_unref(ghostpad);
3687                         goto ERROR;
3688                 }
3689         }
3690
3691         return MM_ERROR_NONE;
3692
3693 ERROR:
3694         g_list_free(element_bucket);
3695
3696         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3697                 LOGE("remove textbin sink from sink list");
3698                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3699         }
3700
3701         /* release element at __mmplayer_gst_create_text_sink_bin */
3702         return MM_ERROR_PLAYER_INTERNAL;
3703 }
3704
3705 static int
3706 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3707 {
3708         mmplayer_gst_element_t *textbin = NULL;
3709         GList *element_bucket = NULL;
3710         int surface_type = 0;
3711         gint i = 0;
3712
3713         MMPLAYER_FENTER();
3714
3715         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3716
3717         /* alloc handles */
3718         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3719         if (!textbin) {
3720                 LOGE("failed to allocate memory for textbin");
3721                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3722         }
3723
3724         /* create bin */
3725         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3726         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3727         if (!textbin[MMPLAYER_T_BIN].gst) {
3728                 LOGE("failed to create textbin");
3729                 goto ERROR;
3730         }
3731
3732         /* take it */
3733         player->pipeline->textbin = textbin;
3734
3735         /* fakesink */
3736         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3737         LOGD("surface type for subtitle : %d", surface_type);
3738         switch (surface_type) {
3739         case MM_DISPLAY_SURFACE_OVERLAY:
3740         case MM_DISPLAY_SURFACE_NULL:
3741         case MM_DISPLAY_SURFACE_REMOTE:
3742                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3743                         LOGE("failed to make plain text elements");
3744                         goto ERROR;
3745                 }
3746                 break;
3747         default:
3748                 goto ERROR;
3749                 break;
3750         }
3751
3752         MMPLAYER_FLEAVE();
3753
3754         return MM_ERROR_NONE;
3755
3756 ERROR:
3757
3758         LOGD("ERROR : releasing textbin");
3759
3760         g_list_free(element_bucket);
3761
3762         /* release signal */
3763         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3764
3765         /* release element which are not added to bin */
3766         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3767                 /* NOTE : skip bin */
3768                 if (textbin[i].gst) {
3769                         GstObject *parent = NULL;
3770                         parent = gst_element_get_parent(textbin[i].gst);
3771
3772                         if (!parent) {
3773                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3774                                 textbin[i].gst = NULL;
3775                         } else {
3776                                 gst_object_unref(GST_OBJECT(parent));
3777                         }
3778                 }
3779         }
3780
3781         /* release textbin with it's childs */
3782         if (textbin[MMPLAYER_T_BIN].gst)
3783                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3784
3785         MMPLAYER_FREEIF(player->pipeline->textbin);
3786         player->pipeline->textbin = NULL;
3787
3788         MMPLAYER_FLEAVE();
3789         return MM_ERROR_PLAYER_INTERNAL;
3790 }
3791
3792 static int
3793 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3794 {
3795         mmplayer_gst_element_t *mainbin = NULL;
3796         mmplayer_gst_element_t *textbin = NULL;
3797         MMHandleType attrs = 0;
3798         GstElement *subsrc = NULL;
3799         GstElement *subparse = NULL;
3800         gchar *subtitle_uri = NULL;
3801         const gchar *charset = NULL;
3802         GstPad *pad = NULL;
3803
3804         MMPLAYER_FENTER();
3805
3806         /* get mainbin */
3807         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3808                                                                 player->pipeline &&
3809                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3810
3811         mainbin = player->pipeline->mainbin;
3812
3813         attrs = MMPLAYER_GET_ATTRS(player);
3814         if (!attrs) {
3815                 LOGE("cannot get content attribute");
3816                 return MM_ERROR_PLAYER_INTERNAL;
3817         }
3818
3819         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3820         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3821                 LOGE("subtitle uri is not proper filepath.");
3822                 return MM_ERROR_PLAYER_INVALID_URI;
3823         }
3824
3825         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3826                 LOGE("failed to get storage info of subtitle path");
3827                 return MM_ERROR_PLAYER_INVALID_URI;
3828         }
3829
3830         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3831
3832         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3833         player->subtitle_language_list = NULL;
3834         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3835
3836         /* create the subtitle source */
3837         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3838         if (!subsrc) {
3839                 LOGE("failed to create filesrc element");
3840                 goto ERROR;
3841         }
3842         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3843
3844         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3845         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3846
3847         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3848                 LOGW("failed to add queue");
3849                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3850                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3851                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3852                 goto ERROR;
3853         }
3854
3855         /* subparse */
3856         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3857         if (!subparse) {
3858                 LOGE("failed to create subparse element");
3859                 goto ERROR;
3860         }
3861
3862         charset = _mmplayer_get_charset(subtitle_uri);
3863         if (charset) {
3864                 LOGD("detected charset is %s", charset);
3865                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3866         }
3867
3868         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3869         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3870
3871         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3872                 LOGW("failed to add subparse");
3873                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3874                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3875                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3876                 goto ERROR;
3877         }
3878
3879         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3880                 LOGW("failed to link subsrc and subparse");
3881                 goto ERROR;
3882         }
3883
3884         player->play_subtitle = TRUE;
3885         player->adjust_subtitle_pos = 0;
3886
3887         LOGD("play subtitle using subtitle file");
3888
3889         if (player->pipeline->textbin == NULL) {
3890                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3891                         LOGE("failed to create text sink bin. continuing without text");
3892                         goto ERROR;
3893                 }
3894
3895                 textbin = player->pipeline->textbin;
3896
3897                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3898                         LOGW("failed to add textbin");
3899
3900                         /* release signal */
3901                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3902
3903                         /* release textbin with it's childs */
3904                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3905                         MMPLAYER_FREEIF(player->pipeline->textbin);
3906                         player->pipeline->textbin = textbin = NULL;
3907                         goto ERROR;
3908                 }
3909
3910                 LOGD("link text input selector and textbin ghost pad");
3911
3912                 player->textsink_linked = 1;
3913                 player->external_text_idx = 0;
3914                 LOGI("textsink is linked");
3915         } else {
3916                 textbin = player->pipeline->textbin;
3917                 LOGD("text bin has been created. reuse it.");
3918                 player->external_text_idx = 1;
3919         }
3920
3921         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3922                 LOGW("failed to link subparse and textbin");
3923                 goto ERROR;
3924         }
3925
3926         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3927         if (!pad) {
3928                 LOGE("failed to get sink pad from textsink to probe data");
3929                 goto ERROR;
3930         }
3931
3932         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3933                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3934
3935         gst_object_unref(pad);
3936         pad = NULL;
3937
3938         /* create dot. for debugging */
3939         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3940         MMPLAYER_FLEAVE();
3941
3942         return MM_ERROR_NONE;
3943
3944 ERROR:
3945         /* release text pipeline resource */
3946         player->textsink_linked = 0;
3947
3948         /* release signal */
3949         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3950
3951         if (player->pipeline->textbin) {
3952                 LOGE("remove textbin");
3953
3954                 /* release textbin with it's childs */
3955                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3956                 MMPLAYER_FREEIF(player->pipeline->textbin);
3957                 player->pipeline->textbin = NULL;
3958
3959         }
3960
3961         /* release subtitle elem */
3962         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3963         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3964
3965         return MM_ERROR_PLAYER_INTERNAL;
3966 }
3967
3968 gboolean
3969 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3970 {
3971         mmplayer_t *player = (mmplayer_t *)data;
3972         MMMessageParamType msg = {0, };
3973         GstClockTime duration = 0;
3974         gpointer text = NULL;
3975         guint text_size = 0;
3976         gboolean ret = TRUE;
3977         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3978
3979         MMPLAYER_FENTER();
3980
3981         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3982         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3983
3984         if (player->is_subtitle_force_drop) {
3985                 LOGW("subtitle is dropped forcedly.");
3986                 return ret;
3987         }
3988
3989         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3990         text = mapinfo.data;
3991         text_size = mapinfo.size;
3992
3993         if (player->set_mode.subtitle_off) {
3994                 LOGD("subtitle is OFF.");
3995                 return TRUE;
3996         }
3997
3998         if (!text || (text_size == 0)) {
3999                 LOGD("There is no subtitle to be displayed.");
4000                 return TRUE;
4001         }
4002
4003         msg.data = (void *)text;
4004
4005         duration = GST_BUFFER_DURATION(buffer);
4006
4007         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4008                 if (player->duration > GST_BUFFER_PTS(buffer))
4009                         duration = player->duration - GST_BUFFER_PTS(buffer);
4010                 else
4011                         duration = 0;
4012                 LOGI("subtitle duration is invalid, subtitle duration change "
4013                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4014         }
4015         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4016
4017         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4018
4019         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4020         gst_buffer_unmap(buffer, &mapinfo);
4021
4022         MMPLAYER_FLEAVE();
4023
4024         return ret;
4025 }
4026
4027 static GstPadProbeReturn
4028 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4029 {
4030         mmplayer_t *player = (mmplayer_t *)u_data;
4031         GstClockTime cur_timestamp = 0;
4032         gint64 adjusted_timestamp = 0;
4033         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4034
4035         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4036
4037         if (player->set_mode.subtitle_off) {
4038                 LOGD("subtitle is OFF.");
4039                 return TRUE;
4040         }
4041
4042         if (player->adjust_subtitle_pos == 0) {
4043                 LOGD("nothing to do");
4044                 return TRUE;
4045         }
4046
4047         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4048         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4049
4050         if (adjusted_timestamp < 0) {
4051                 LOGD("adjusted_timestamp under zero");
4052                 MMPLAYER_FLEAVE();
4053                 return FALSE;
4054         }
4055
4056         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4057         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4058                                 GST_TIME_ARGS(cur_timestamp),
4059                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4060
4061         return GST_PAD_PROBE_OK;
4062 }
4063
4064 static int
4065 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4066 {
4067         MMPLAYER_FENTER();
4068
4069         /* check player and subtitlebin are created */
4070         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4071         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4072
4073         if (position == 0) {
4074                 LOGD("nothing to do");
4075                 MMPLAYER_FLEAVE();
4076                 return MM_ERROR_NONE;
4077         }
4078
4079         /* check current postion */
4080         player->adjust_subtitle_pos = position;
4081
4082         LOGD("save adjust_subtitle_pos in player");
4083
4084         MMPLAYER_FLEAVE();
4085
4086         return MM_ERROR_NONE;
4087 }
4088
4089 /**
4090  * This function is to create  audio or video pipeline for playing.
4091  *
4092  * @param       player          [in]    handle of player
4093  *
4094  * @return      This function returns zero on success.
4095  * @remark
4096  * @see
4097  */
4098 static int
4099 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4100 {
4101         int ret = MM_ERROR_NONE;
4102         mmplayer_gst_element_t *mainbin = NULL;
4103         MMHandleType attrs = 0;
4104
4105         MMPLAYER_FENTER();
4106         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4107
4108         /* get profile attribute */
4109         attrs = MMPLAYER_GET_ATTRS(player);
4110         if (!attrs) {
4111                 LOGE("failed to get content attribute");
4112                 goto INIT_ERROR;
4113         }
4114
4115         /* create pipeline handles */
4116         if (player->pipeline) {
4117                 LOGE("pipeline should be released before create new one");
4118                 goto INIT_ERROR;
4119         }
4120
4121         player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4122
4123         /* create mainbin */
4124         mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4125         if (mainbin == NULL)
4126                 goto INIT_ERROR;
4127
4128         /* create pipeline */
4129         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4130         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4131         if (!mainbin[MMPLAYER_M_PIPE].gst) {
4132                 LOGE("failed to create pipeline");
4133                 g_free(mainbin);
4134                 goto INIT_ERROR;
4135         }
4136
4137         player->pipeline->mainbin = mainbin;
4138
4139         /* create the source and decoder elements */
4140         if (MMPLAYER_IS_MS_BUFF_SRC(player))
4141                 ret = _mmplayer_gst_build_es_pipeline(player);
4142         else
4143                 ret = _mmplayer_gst_build_pipeline(player);
4144
4145         if (ret != MM_ERROR_NONE) {
4146                 LOGE("failed to create some elements");
4147                 goto INIT_ERROR;
4148         }
4149
4150         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4151         if (__mmplayer_check_subtitle(player)
4152                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4153                 LOGE("failed to create text pipeline");
4154
4155         /* add bus watch */
4156         ret = _mmplayer_gst_add_bus_watch(player);
4157         if (ret != MM_ERROR_NONE) {
4158                 LOGE("failed to add bus watch");
4159                 goto INIT_ERROR;
4160         }
4161
4162         MMPLAYER_FLEAVE();
4163         return MM_ERROR_NONE;
4164
4165 INIT_ERROR:
4166         __mmplayer_gst_destroy_pipeline(player);
4167         return MM_ERROR_PLAYER_INTERNAL;
4168 }
4169
4170 static void
4171 __mmplayer_reset_gapless_state(mmplayer_t *player)
4172 {
4173         MMPLAYER_FENTER();
4174         MMPLAYER_RETURN_IF_FAIL(player
4175                 && player->pipeline
4176                 && player->pipeline->audiobin
4177                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4178
4179         memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4180
4181         MMPLAYER_FLEAVE();
4182         return;
4183 }
4184
4185 static int
4186 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4187 {
4188         gint timeout = 0;
4189         int ret = MM_ERROR_NONE;
4190
4191         MMPLAYER_FENTER();
4192
4193         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4194
4195         /* cleanup stuffs */
4196         MMPLAYER_FREEIF(player->type);
4197         player->no_more_pad = FALSE;
4198         player->num_dynamic_pad = 0;
4199         player->demux_pad_index = 0;
4200
4201         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4202         player->subtitle_language_list = NULL;
4203         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4204
4205         __mmplayer_reset_gapless_state(player);
4206
4207         if (player->streamer) {
4208                 _mm_player_streaming_initialize(player->streamer, FALSE);
4209                 _mm_player_streaming_destroy(player->streamer);
4210                 player->streamer = NULL;
4211         }
4212
4213         /* cleanup unlinked mime type */
4214         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4215         MMPLAYER_FREEIF(player->unlinked_video_mime);
4216         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4217
4218         /* cleanup running stuffs */
4219         _mmplayer_cancel_eos_timer(player);
4220
4221         /* cleanup gst stuffs */
4222         if (player->pipeline) {
4223                 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4224                 GstTagList *tag_list = player->pipeline->tag_list;
4225
4226                 /* first we need to disconnect all signal hander */
4227                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4228
4229                 if (mainbin) {
4230                         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4231                         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4232                         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4233                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4234                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4235                         gst_object_unref(bus);
4236
4237                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4238                         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4239                         if (ret != MM_ERROR_NONE) {
4240                                 LOGE("fail to change state to NULL");
4241                                 return MM_ERROR_PLAYER_INTERNAL;
4242                         }
4243
4244                         LOGW("succeeded in changing state to NULL");
4245
4246                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4247
4248                         /* free fakesink */
4249                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4250                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4251
4252                         /* free avsysaudiosink
4253                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4254                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4255                         */
4256                         MMPLAYER_FREEIF(audiobin);
4257                         MMPLAYER_FREEIF(videobin);
4258                         MMPLAYER_FREEIF(textbin);
4259                         MMPLAYER_FREEIF(mainbin);
4260                 }
4261
4262                 if (tag_list)
4263                         gst_tag_list_unref(tag_list);
4264
4265                 MMPLAYER_FREEIF(player->pipeline);
4266         }
4267         MMPLAYER_FREEIF(player->album_art);
4268
4269         if (player->v_stream_caps) {
4270                 gst_caps_unref(player->v_stream_caps);
4271                 player->v_stream_caps = NULL;
4272         }
4273
4274         if (player->a_stream_caps) {
4275                 gst_caps_unref(player->a_stream_caps);
4276                 player->a_stream_caps = NULL;
4277         }
4278
4279         if (player->s_stream_caps) {
4280                 gst_caps_unref(player->s_stream_caps);
4281                 player->s_stream_caps = NULL;
4282         }
4283         _mmplayer_track_destroy(player);
4284
4285         if (player->sink_elements)
4286                 g_list_free(player->sink_elements);
4287         player->sink_elements = NULL;
4288
4289         if (player->bufmgr) {
4290                 tbm_bufmgr_deinit(player->bufmgr);
4291                 player->bufmgr = NULL;
4292         }
4293
4294         LOGW("finished destroy pipeline");
4295
4296         MMPLAYER_FLEAVE();
4297
4298         return ret;
4299 }
4300
4301 static int
4302 __mmplayer_gst_realize(mmplayer_t *player)
4303 {
4304         gint timeout = 0;
4305         int ret = MM_ERROR_NONE;
4306
4307         MMPLAYER_FENTER();
4308
4309         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4310
4311         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4312
4313         ret = __mmplayer_gst_create_pipeline(player);
4314         if (ret) {
4315                 LOGE("failed to create pipeline");
4316                 return ret;
4317         }
4318
4319         /* set pipeline state to READY */
4320         /* NOTE : state change to READY must be performed sync. */
4321         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4322         ret = _mmplayer_gst_set_state(player,
4323                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4324
4325         if (ret != MM_ERROR_NONE) {
4326                 /* return error if failed to set state */
4327                 LOGE("failed to set READY state");
4328                 return ret;
4329         }
4330
4331         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4332
4333         /* create dot before error-return. for debugging */
4334         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4335
4336         MMPLAYER_FLEAVE();
4337
4338         return ret;
4339 }
4340
4341 static int
4342 __mmplayer_gst_unrealize(mmplayer_t *player)
4343 {
4344         int ret = MM_ERROR_NONE;
4345
4346         MMPLAYER_FENTER();
4347
4348         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4349
4350         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4351         MMPLAYER_PRINT_STATE(player);
4352
4353         /* release miscellaneous information */
4354         __mmplayer_release_misc(player);
4355
4356         /* destroy pipeline */
4357         ret = __mmplayer_gst_destroy_pipeline(player);
4358         if (ret != MM_ERROR_NONE) {
4359                 LOGE("failed to destory pipeline");
4360                 return ret;
4361         }
4362
4363         /* release miscellaneous information.
4364            these info needs to be released after pipeline is destroyed. */
4365         __mmplayer_release_misc_post(player);
4366
4367         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4368
4369         MMPLAYER_FLEAVE();
4370
4371         return ret;
4372 }
4373
4374 static int
4375 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4376 {
4377         MMPLAYER_FENTER();
4378
4379         if (!player) {
4380                 LOGW("set_message_callback is called with invalid player handle");
4381                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4382         }
4383
4384         player->msg_cb = callback;
4385         player->msg_cb_param = user_param;
4386
4387         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4388
4389         MMPLAYER_FLEAVE();
4390
4391         return MM_ERROR_NONE;
4392 }
4393
4394 int
4395 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4396 {
4397         int ret = MM_ERROR_NONE;
4398         char *path = NULL;
4399
4400         MMPLAYER_FENTER();
4401
4402         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4403         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4404         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4405
4406         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4407
4408         if (strstr(uri, "es_buff://")) {
4409                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4410         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4411                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4412         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4413                 gchar *tmp = NULL;
4414                 tmp = g_ascii_strdown(uri, strlen(uri));
4415                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4416                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4417                 else
4418                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4419                 g_free(tmp);
4420         } else if (strstr(uri, "mms://")) {
4421                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4422         } else if ((path = strstr(uri, "mem://"))) {
4423                 ret = __mmplayer_set_mem_uri(data, path, param);
4424         } else {
4425                 ret = __mmplayer_set_file_uri(data, uri);
4426         }
4427
4428         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4429                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4430         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4431                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4432
4433         /* dump parse result */
4434         SECURE_LOGW("incoming uri : %s", uri);
4435         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4436                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4437
4438         MMPLAYER_FLEAVE();
4439
4440         return ret;
4441 }
4442
4443 static gboolean
4444 __mmplayer_can_do_interrupt(mmplayer_t *player)
4445 {
4446         if (!player || !player->pipeline || !player->attrs) {
4447                 LOGW("not initialized");
4448                 goto FAILED;
4449         }
4450
4451         if (player->audio_decoded_cb) {
4452                 LOGW("not support in pcm extraction mode");
4453                 goto FAILED;
4454         }
4455
4456         /* check if seeking */
4457         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4458                 MMMessageParamType msg_param;
4459                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4460                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4461                 player->seek_state = MMPLAYER_SEEK_NONE;
4462                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4463                 goto FAILED;
4464         }
4465
4466         /* check other thread */
4467         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4468                 LOGW("locked already, cmd state : %d", player->cmd);
4469
4470                 /* check application command */
4471                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4472                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4473
4474                         /* lock will be released at mrp_resource_release_cb() */
4475                         MMPLAYER_CMD_LOCK(player);
4476                         goto INTERRUPT;
4477                 }
4478                 LOGW("nothing to do");
4479                 goto FAILED;
4480         } else {
4481                 LOGW("can interrupt immediately");
4482                 goto INTERRUPT;
4483         }
4484
4485 FAILED:    /* with CMD UNLOCKED */
4486         return FALSE;
4487
4488 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4489         return TRUE;
4490 }
4491
4492 static int
4493 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4494                 void *user_data)
4495 {
4496         mmplayer_t *player = NULL;
4497         MMMessageParamType msg = {0, };
4498         gint64 pos = 0;
4499         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4500
4501         MMPLAYER_FENTER();
4502
4503         if (!user_data) {
4504                 LOGE("user_data is null");
4505                 return FALSE;
4506         }
4507         player = (mmplayer_t *)user_data;
4508
4509         if (!__mmplayer_can_do_interrupt(player)) {
4510                 LOGW("no need to interrupt, so leave");
4511                 /* FIXME: there is no way to avoid releasing resource. */
4512                 return FALSE;
4513         }
4514
4515         player->interrupted_by_resource = TRUE;
4516
4517         /* get last play position */
4518         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4519                 msg.union_type = MM_MSG_UNION_TIME;
4520                 msg.time.elapsed = pos;
4521                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4522         } else {
4523                 LOGW("failed to get play position.");
4524         }
4525
4526         LOGD("video resource conflict so, resource will be freed by unrealizing");
4527         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4528                 LOGE("failed to unrealize");
4529
4530         /* lock is called in __mmplayer_can_do_interrupt() */
4531         MMPLAYER_CMD_UNLOCK(player);
4532
4533         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4534                 player->hw_resource[res_idx] = NULL;
4535         }
4536
4537         MMPLAYER_FLEAVE();
4538         return TRUE; /* release all the resources */
4539 }
4540
4541 static void
4542 __mmplayer_initialize_video_roi(mmplayer_t *player)
4543 {
4544         player->video_roi.scale_x = 0.0;
4545         player->video_roi.scale_y = 0.0;
4546         player->video_roi.scale_width = 1.0;
4547         player->video_roi.scale_height = 1.0;
4548 }
4549
4550 int
4551 _mmplayer_create_player(MMHandleType handle)
4552 {
4553         int ret = MM_ERROR_PLAYER_INTERNAL;
4554         bool enabled = false;
4555
4556         mmplayer_t *player = MM_PLAYER_CAST(handle);
4557
4558         MMPLAYER_FENTER();
4559
4560         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4561
4562         /* initialize player state */
4563         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4564         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4565         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4566         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4567
4568         /* check current state */
4569         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4570
4571         /* construct attributes */
4572         player->attrs = _mmplayer_construct_attribute(handle);
4573
4574         if (!player->attrs) {
4575                 LOGE("Failed to construct attributes");
4576                 return ret;
4577         }
4578
4579         /* initialize gstreamer with configured parameter */
4580         if (!__mmplayer_init_gstreamer(player)) {
4581                 LOGE("Initializing gstreamer failed");
4582                 _mmplayer_deconstruct_attribute(handle);
4583                 return ret;
4584         }
4585
4586         /* create lock. note that g_tread_init() has already called in gst_init() */
4587         g_mutex_init(&player->fsink_lock);
4588
4589         /* create update tag lock */
4590         g_mutex_init(&player->update_tag_lock);
4591
4592         /* create gapless play mutex */
4593         g_mutex_init(&player->gapless_play_thread_mutex);
4594
4595         /* create gapless play cond */
4596         g_cond_init(&player->gapless_play_thread_cond);
4597
4598         /* create gapless play thread */
4599         player->gapless_play_thread =
4600                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4601         if (!player->gapless_play_thread) {
4602                 LOGE("failed to create gapless play thread");
4603                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4604                 g_mutex_clear(&player->gapless_play_thread_mutex);
4605                 g_cond_clear(&player->gapless_play_thread_cond);
4606                 goto ERROR;
4607         }
4608
4609         player->bus_msg_q = g_queue_new();
4610         if (!player->bus_msg_q) {
4611                 LOGE("failed to create queue for bus_msg");
4612                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4613                 goto ERROR;
4614         }
4615
4616         ret = _mmplayer_initialize_video_capture(player);
4617         if (ret != MM_ERROR_NONE) {
4618                 LOGE("failed to initialize video capture");
4619                 goto ERROR;
4620         }
4621
4622         /* initialize resource manager */
4623         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4624                 __resource_release_cb, player, &player->resource_manager)
4625                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4626                 LOGE("failed to initialize resource manager");
4627                 ret = MM_ERROR_PLAYER_INTERNAL;
4628                 goto ERROR;
4629         }
4630
4631         /* create video bo lock and cond */
4632         g_mutex_init(&player->video_bo_mutex);
4633         g_cond_init(&player->video_bo_cond);
4634
4635         /* create subtitle info lock and cond */
4636         g_mutex_init(&player->subtitle_info_mutex);
4637         g_cond_init(&player->subtitle_info_cond);
4638
4639         player->streaming_type = STREAMING_SERVICE_NONE;
4640
4641         /* give default value of audio effect setting */
4642         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4643         player->sound.rg_enable = false;
4644         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4645
4646         player->play_subtitle = FALSE;
4647         player->has_closed_caption = FALSE;
4648         player->pending_resume = FALSE;
4649         if (player->ini.dump_element_keyword[0][0] == '\0')
4650                 player->ini.set_dump_element_flag = FALSE;
4651         else
4652                 player->ini.set_dump_element_flag = TRUE;
4653
4654         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4655         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4656         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4657
4658         /* Set video360 settings to their defaults for just-created player.
4659          * */
4660
4661         player->is_360_feature_enabled = FALSE;
4662         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4663                 LOGI("spherical feature info: %d", enabled);
4664                 if (enabled)
4665                         player->is_360_feature_enabled = TRUE;
4666         } else {
4667                 LOGE("failed to get spherical feature info");
4668         }
4669
4670         player->is_content_spherical = FALSE;
4671         player->is_video360_enabled = TRUE;
4672         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4673         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4674         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4675         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4676         player->video360_zoom = 1.0f;
4677         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4678         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4679
4680         __mmplayer_initialize_video_roi(player);
4681
4682         /* set player state to null */
4683         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4684         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4685
4686         MMPLAYER_FLEAVE();
4687
4688         return MM_ERROR_NONE;
4689
4690 ERROR:
4691         /* free lock */
4692         g_mutex_clear(&player->fsink_lock);
4693         /* free update tag lock */
4694         g_mutex_clear(&player->update_tag_lock);
4695         g_queue_free(player->bus_msg_q);
4696         player->bus_msg_q = NULL;
4697         /* free gapless play thread */
4698         if (player->gapless_play_thread) {
4699                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4700                 player->gapless_play_thread_exit = TRUE;
4701                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4702                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4703
4704                 g_thread_join(player->gapless_play_thread);
4705                 player->gapless_play_thread = NULL;
4706
4707                 g_mutex_clear(&player->gapless_play_thread_mutex);
4708                 g_cond_clear(&player->gapless_play_thread_cond);
4709         }
4710
4711         /* release attributes */
4712         _mmplayer_deconstruct_attribute(handle);
4713
4714         MMPLAYER_FLEAVE();
4715
4716         return ret;
4717 }
4718
4719 static gboolean
4720 __mmplayer_init_gstreamer(mmplayer_t *player)
4721 {
4722         static gboolean initialized = FALSE;
4723         static const int max_argc = 50;
4724         gint *argc = NULL;
4725         gchar **argv = NULL;
4726         gchar **argv2 = NULL;
4727         GError *err = NULL;
4728         int i = 0;
4729         int arg_count = 0;
4730
4731         if (initialized) {
4732                 LOGD("gstreamer already initialized.");
4733                 return TRUE;
4734         }
4735
4736         /* alloc */
4737         argc = malloc(sizeof(int));
4738         argv = malloc(sizeof(gchar *) * max_argc);
4739         argv2 = malloc(sizeof(gchar *) * max_argc);
4740
4741         if (!argc || !argv || !argv2)
4742                 goto ERROR;
4743
4744         memset(argv, 0, sizeof(gchar *) * max_argc);
4745         memset(argv2, 0, sizeof(gchar *) * max_argc);
4746
4747         /* add initial */
4748         *argc = 1;
4749         argv[0] = g_strdup("mmplayer");
4750
4751         /* add gst_param */
4752         for (i = 0; i < 5; i++) {
4753                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4754                 if (strlen(player->ini.gst_param[i]) > 0) {
4755                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4756                         (*argc)++;
4757                 }
4758         }
4759
4760         /* we would not do fork for scanning plugins */
4761         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4762         (*argc)++;
4763
4764         /* check disable registry scan */
4765         if (player->ini.skip_rescan) {
4766                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4767                 (*argc)++;
4768         }
4769
4770         /* check disable segtrap */
4771         if (player->ini.disable_segtrap) {
4772                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4773                 (*argc)++;
4774         }
4775
4776         LOGD("initializing gstreamer with following parameter");
4777         LOGD("argc : %d", *argc);
4778         arg_count = *argc;
4779
4780         for (i = 0; i < arg_count; i++) {
4781                 argv2[i] = argv[i];
4782                 LOGD("argv[%d] : %s", i, argv2[i]);
4783         }
4784
4785         /* initializing gstreamer */
4786         if (!gst_init_check(argc, &argv, &err)) {
4787                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4788                 if (err)
4789                         g_error_free(err);
4790
4791                 goto ERROR;
4792         }
4793         /* release */
4794         for (i = 0; i < arg_count; i++) {
4795 #ifdef __DEBUG__
4796                 LOGD("release - argv[%d] : %s", i, argv2[i]);
4797 #endif
4798                 MMPLAYER_FREEIF(argv2[i]);
4799         }
4800
4801         MMPLAYER_FREEIF(argv);
4802         MMPLAYER_FREEIF(argv2);
4803         MMPLAYER_FREEIF(argc);
4804
4805         /* done */
4806         initialized = TRUE;
4807
4808         return TRUE;
4809
4810 ERROR:
4811
4812         /* release */
4813         for (i = 0; i < arg_count; i++) {
4814                 LOGD("free[%d] : %s", i, argv2[i]);
4815                 MMPLAYER_FREEIF(argv2[i]);
4816         }
4817
4818         MMPLAYER_FREEIF(argv);
4819         MMPLAYER_FREEIF(argv2);
4820         MMPLAYER_FREEIF(argc);
4821
4822         return FALSE;
4823 }
4824
4825 static void
4826 __mmplayer_check_async_state_transition(mmplayer_t *player)
4827 {
4828         GstState element_state = GST_STATE_VOID_PENDING;
4829         GstState element_pending_state = GST_STATE_VOID_PENDING;
4830         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4831         GstElement *element = NULL;
4832         gboolean async = FALSE;
4833
4834         /* check player handle */
4835         MMPLAYER_RETURN_IF_FAIL(player &&
4836                                                 player->pipeline &&
4837                                                 player->pipeline->mainbin &&
4838                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4839
4840         if (player->attrs)
4841                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4842
4843         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4844                 LOGD("don't need to check the pipeline state");
4845                 return;
4846         }
4847
4848         MMPLAYER_PRINT_STATE(player);
4849
4850         /* wait for state transition */
4851         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4852         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4853
4854         if (ret == GST_STATE_CHANGE_FAILURE) {
4855                 LOGE(" [%s] state : %s   pending : %s",
4856                         GST_ELEMENT_NAME(element),
4857                         gst_element_state_get_name(element_state),
4858                         gst_element_state_get_name(element_pending_state));
4859
4860                 /* dump state of all element */
4861                 _mmplayer_dump_pipeline_state(player);
4862
4863                 return;
4864         }
4865
4866         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4867         return;
4868 }
4869
4870 int
4871 _mmplayer_destroy(MMHandleType handle)
4872 {
4873         mmplayer_t *player = MM_PLAYER_CAST(handle);
4874
4875         MMPLAYER_FENTER();
4876
4877         /* check player handle */
4878         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4879
4880         /* destroy can called at anytime */
4881         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4882
4883         /* check async state transition */
4884         __mmplayer_check_async_state_transition(player);
4885
4886         /* release gapless play thread */
4887         if (player->gapless_play_thread) {
4888                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4889                 player->gapless_play_thread_exit = TRUE;
4890                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4891                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4892
4893                 LOGD("waitting for gapless play thread exit");
4894                 g_thread_join(player->gapless_play_thread);
4895                 g_mutex_clear(&player->gapless_play_thread_mutex);
4896                 g_cond_clear(&player->gapless_play_thread_cond);
4897                 LOGD("gapless play thread released");
4898         }
4899
4900         _mmplayer_release_video_capture(player);
4901
4902         /* de-initialize resource manager */
4903         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4904                         player->resource_manager))
4905                 LOGE("failed to deinitialize resource manager");
4906
4907         /* release pipeline */
4908         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4909                 LOGE("failed to destory pipeline");
4910                 return MM_ERROR_PLAYER_INTERNAL;
4911         }
4912
4913         g_queue_free(player->bus_msg_q);
4914
4915         /* release subtitle info lock and cond */
4916         g_mutex_clear(&player->subtitle_info_mutex);
4917         g_cond_clear(&player->subtitle_info_cond);
4918
4919         __mmplayer_release_dump_list(player->dump_list);
4920
4921         /* release miscellaneous information */
4922         __mmplayer_release_misc(player);
4923
4924         /* release miscellaneous information.
4925            these info needs to be released after pipeline is destroyed. */
4926         __mmplayer_release_misc_post(player);
4927
4928         /* release attributes */
4929         _mmplayer_deconstruct_attribute(handle);
4930
4931         /* release lock */
4932         g_mutex_clear(&player->fsink_lock);
4933
4934         /* release lock */
4935         g_mutex_clear(&player->update_tag_lock);
4936
4937         /* release video bo lock and cond */
4938         g_mutex_clear(&player->video_bo_mutex);
4939         g_cond_clear(&player->video_bo_cond);
4940
4941         MMPLAYER_FLEAVE();
4942
4943         return MM_ERROR_NONE;
4944 }
4945
4946 int
4947 _mmplayer_realize(MMHandleType hplayer)
4948 {
4949         mmplayer_t *player = (mmplayer_t *)hplayer;
4950         char *uri = NULL;
4951         void *param = NULL;
4952         MMHandleType attrs = 0;
4953         int ret = MM_ERROR_NONE;
4954
4955         MMPLAYER_FENTER();
4956
4957         /* check player handle */
4958         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4959
4960         /* check current state */
4961         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4962
4963         attrs = MMPLAYER_GET_ATTRS(player);
4964         if (!attrs) {
4965                 LOGE("fail to get attributes.");
4966                 return MM_ERROR_PLAYER_INTERNAL;
4967         }
4968         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4969         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
4970
4971         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4972                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4973
4974                 if (ret != MM_ERROR_NONE) {
4975                         LOGE("failed to parse profile");
4976                         return ret;
4977                 }
4978         }
4979
4980         if (uri && (strstr(uri, "es_buff://"))) {
4981                 if (strstr(uri, "es_buff://push_mode"))
4982                         player->es_player_push_mode = TRUE;
4983                 else
4984                         player->es_player_push_mode = FALSE;
4985         }
4986
4987         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4988                 LOGW("mms protocol is not supported format.");
4989                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4990         }
4991
4992         if (MMPLAYER_IS_STREAMING(player))
4993                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4994         else
4995                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4996
4997         player->smooth_streaming = FALSE;
4998         player->videodec_linked  = 0;
4999         player->audiodec_linked  = 0;
5000         player->textsink_linked = 0;
5001         player->is_external_subtitle_present = FALSE;
5002         player->is_external_subtitle_added_now = FALSE;
5003         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5004         player->video360_metadata.is_spherical = -1;
5005         player->is_openal_plugin_used = FALSE;
5006         player->demux_pad_index = 0;
5007         player->subtitle_language_list = NULL;
5008         player->is_subtitle_force_drop = FALSE;
5009
5010         _mmplayer_track_initialize(player);
5011         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5012
5013         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5014                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5015
5016                 player->streamer = _mm_player_streaming_create();
5017                 _mm_player_streaming_initialize(player->streamer, TRUE);
5018
5019                 mm_attrs_multiple_get(player->attrs, NULL,
5020                                 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5021                                 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5022
5023                 if (prebuffer_ms > 0) {
5024                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5025                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5026                 }
5027
5028                 if (rebuffer_ms > 0) {
5029                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5030                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5031                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5032                 }
5033
5034                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5035                                                                 player->streamer->buffering_req.rebuffer_time);
5036         }
5037
5038         /* realize pipeline */
5039         ret = __mmplayer_gst_realize(player);
5040         if (ret != MM_ERROR_NONE)
5041                 LOGE("fail to realize the player.");
5042
5043         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5044
5045         MMPLAYER_FLEAVE();
5046
5047         return ret;
5048 }
5049
5050 int
5051 _mmplayer_unrealize(MMHandleType hplayer)
5052 {
5053         mmplayer_t *player = (mmplayer_t *)hplayer;
5054         int ret = MM_ERROR_NONE;
5055
5056         MMPLAYER_FENTER();
5057
5058         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5059
5060         MMPLAYER_CMD_UNLOCK(player);
5061         /* destroy the gst bus msg thread which is created during realize.
5062            this funct have to be called before getting cmd lock. */
5063         _mmplayer_bus_msg_thread_destroy(player);
5064         MMPLAYER_CMD_LOCK(player);
5065
5066         /* check current state */
5067         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5068
5069         /* check async state transition */
5070         __mmplayer_check_async_state_transition(player);
5071
5072         /* unrealize pipeline */
5073         ret = __mmplayer_gst_unrealize(player);
5074
5075         if (!player->interrupted_by_resource) {
5076                 int rm_ret = MM_ERROR_NONE;
5077                 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5078
5079                 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5080                         rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5081                         if (rm_ret != MM_ERROR_NONE)
5082                                 LOGE("failed to release [%d] resources", res_idx);
5083                 }
5084         }
5085
5086         MMPLAYER_FLEAVE();
5087         return ret;
5088 }
5089
5090 int
5091 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5092 {
5093         mmplayer_t *player = (mmplayer_t *)hplayer;
5094
5095         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5096
5097         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5098 }
5099
5100 int
5101 _mmplayer_get_state(MMHandleType hplayer, int *state)
5102 {
5103         mmplayer_t *player = (mmplayer_t *)hplayer;
5104
5105         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5106
5107         *state = MMPLAYER_CURRENT_STATE(player);
5108
5109         return MM_ERROR_NONE;
5110 }
5111
5112 static int
5113 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5114 {
5115         GstElement *vol_element = NULL;
5116         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5117
5118         MMPLAYER_FENTER();
5119         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5120         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5121
5122         /* check pipeline handle */
5123         if (!player->pipeline || !player->pipeline->audiobin) {
5124                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5125
5126                 /* NOTE : stored value will be used in create_audiobin
5127                  * returning MM_ERROR_NONE here makes application to able to
5128                  * set audio volume or mute at anytime.
5129                  */
5130                 return MM_ERROR_NONE;
5131         }
5132
5133         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5134                 volume_elem_id = MMPLAYER_A_SINK;
5135
5136         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5137         if (!vol_element) {
5138                 LOGE("failed to get vol element %d", volume_elem_id);
5139                 return MM_ERROR_PLAYER_INTERNAL;
5140         }
5141
5142         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5143
5144         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5145                 LOGE("there is no '%s' property", prop_name);
5146                 return MM_ERROR_PLAYER_INTERNAL;
5147         }
5148
5149         if (!strcmp(prop_name, "volume")) {
5150                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5151         } else if (!strcmp(prop_name, "mute")) {
5152                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5153         } else {
5154                 LOGE("invalid property %s", prop_name);
5155                 return MM_ERROR_PLAYER_INTERNAL;
5156         }
5157
5158         return MM_ERROR_NONE;
5159 }
5160
5161 int
5162 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5163 {
5164         int ret = MM_ERROR_NONE;
5165         mmplayer_t *player = (mmplayer_t *)hplayer;
5166
5167         MMPLAYER_FENTER();
5168         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169
5170         LOGD("volume = %f", volume);
5171
5172         /* invalid factor range or not */
5173         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5174                 LOGE("Invalid volume value");
5175                 return MM_ERROR_INVALID_ARGUMENT;
5176         }
5177
5178         player->sound.volume = volume;
5179
5180         ret = __mmplayer_gst_set_volume_property(player, "volume");
5181
5182         MMPLAYER_FLEAVE();
5183         return ret;
5184 }
5185
5186 int
5187 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5188 {
5189         mmplayer_t *player = (mmplayer_t *)hplayer;
5190
5191         MMPLAYER_FENTER();
5192
5193         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5194         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5195
5196         *volume = player->sound.volume;
5197
5198         LOGD("current vol = %f", *volume);
5199
5200         MMPLAYER_FLEAVE();
5201         return MM_ERROR_NONE;
5202 }
5203
5204 int
5205 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5206 {
5207         int ret = MM_ERROR_NONE;
5208         mmplayer_t *player = (mmplayer_t *)hplayer;
5209
5210         MMPLAYER_FENTER();
5211         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5212
5213         LOGD("mute = %d", mute);
5214
5215         player->sound.mute = mute;
5216
5217         ret = __mmplayer_gst_set_volume_property(player, "mute");
5218
5219         MMPLAYER_FLEAVE();
5220         return ret;
5221 }
5222
5223 int
5224 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5225 {
5226         mmplayer_t *player = (mmplayer_t *)hplayer;
5227
5228         MMPLAYER_FENTER();
5229
5230         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5232
5233         *mute = player->sound.mute;
5234
5235         LOGD("current mute = %d", *mute);
5236
5237         MMPLAYER_FLEAVE();
5238
5239         return MM_ERROR_NONE;
5240 }
5241
5242 int
5243 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5244 {
5245         mmplayer_t *player = (mmplayer_t *)hplayer;
5246
5247         MMPLAYER_FENTER();
5248
5249         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5250
5251         player->audio_stream_changed_cb = callback;
5252         player->audio_stream_changed_cb_user_param = user_param;
5253         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5254
5255         MMPLAYER_FLEAVE();
5256
5257         return MM_ERROR_NONE;
5258 }
5259
5260 int
5261 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5262 {
5263         mmplayer_t *player = (mmplayer_t *)hplayer;
5264
5265         MMPLAYER_FENTER();
5266
5267         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5268
5269         player->audio_decoded_cb = callback;
5270         player->audio_decoded_cb_user_param = user_param;
5271         player->audio_extract_opt = opt;
5272         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5273
5274         MMPLAYER_FLEAVE();
5275
5276         return MM_ERROR_NONE;
5277 }
5278
5279 int
5280 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5281 {
5282         mmplayer_t *player = (mmplayer_t *)hplayer;
5283
5284         MMPLAYER_FENTER();
5285
5286         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5287
5288         if (callback && !player->bufmgr)
5289                 player->bufmgr = tbm_bufmgr_init(-1);
5290
5291         player->set_mode.video_export = (callback) ? true : false;
5292         player->video_decoded_cb = callback;
5293         player->video_decoded_cb_user_param = user_param;
5294
5295         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5296
5297         MMPLAYER_FLEAVE();
5298
5299         return MM_ERROR_NONE;
5300 }
5301
5302 int
5303 _mmplayer_start(MMHandleType hplayer)
5304 {
5305         mmplayer_t *player = (mmplayer_t *)hplayer;
5306         gint ret = MM_ERROR_NONE;
5307
5308         MMPLAYER_FENTER();
5309
5310         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5311
5312         /* check current state */
5313         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5314
5315         /* start pipeline */
5316         ret = _mmplayer_gst_start(player);
5317         if (ret != MM_ERROR_NONE)
5318                 LOGE("failed to start player.");
5319
5320         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5321                 LOGD("force playing start even during buffering");
5322                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5323         }
5324
5325         MMPLAYER_FLEAVE();
5326
5327         return ret;
5328 }
5329
5330 /* NOTE: post "not supported codec message" to application
5331  * when one codec is not found during AUTOPLUGGING in MSL.
5332  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5333  * And, if any codec is not found, don't send message here.
5334  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5335  */
5336 int
5337 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5338 {
5339         MMMessageParamType msg_param;
5340         memset(&msg_param, 0, sizeof(MMMessageParamType));
5341         gboolean post_msg_direct = FALSE;
5342
5343         MMPLAYER_FENTER();
5344
5345         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346
5347         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5348                         player->not_supported_codec, player->can_support_codec);
5349
5350         if (player->not_found_demuxer) {
5351                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5352                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5353
5354                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5355                 MMPLAYER_FREEIF(msg_param.data);
5356
5357                 return MM_ERROR_NONE;
5358         }
5359
5360         if (player->not_supported_codec) {
5361                 if (player->can_support_codec) {
5362                         // There is one codec to play
5363                         post_msg_direct = TRUE;
5364                 } else {
5365                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5366                                 post_msg_direct = TRUE;
5367                 }
5368
5369                 if (post_msg_direct) {
5370                         MMMessageParamType msg_param;
5371                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5372
5373                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5374                                 LOGW("not found AUDIO codec, posting error code to application.");
5375
5376                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5377                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5378                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5379                                 LOGW("not found VIDEO codec, posting error code to application.");
5380
5381                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5382                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5383                         }
5384
5385                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5386
5387                         MMPLAYER_FREEIF(msg_param.data);
5388
5389                         return MM_ERROR_NONE;
5390                 } else {
5391                         // no any supported codec case
5392                         LOGW("not found any codec, posting error code to application.");
5393
5394                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5395                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5396                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5397                         } else {
5398                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5399                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5400                         }
5401
5402                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5403
5404                         MMPLAYER_FREEIF(msg_param.data);
5405                 }
5406         }
5407
5408         MMPLAYER_FLEAVE();
5409
5410         return MM_ERROR_NONE;
5411 }
5412
5413 static void
5414 __mmplayer_check_pipeline(mmplayer_t *player)
5415 {
5416         GstState element_state = GST_STATE_VOID_PENDING;
5417         GstState element_pending_state = GST_STATE_VOID_PENDING;
5418         gint timeout = 0;
5419         int ret = MM_ERROR_NONE;
5420
5421         if (!player->gapless.reconfigure)
5422                 return;
5423
5424         LOGW("pipeline is under construction.");
5425
5426         MMPLAYER_PLAYBACK_LOCK(player);
5427         MMPLAYER_PLAYBACK_UNLOCK(player);
5428
5429         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5430
5431         /* wait for state transition */
5432         ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5433         if (ret == GST_STATE_CHANGE_FAILURE)
5434                 LOGE("failed to change pipeline state within %d sec", timeout);
5435 }
5436
5437 /* NOTE : it should be able to call 'stop' anytime*/
5438 int
5439 _mmplayer_stop(MMHandleType hplayer)
5440 {
5441         mmplayer_t *player = (mmplayer_t *)hplayer;
5442         int ret = MM_ERROR_NONE;
5443
5444         MMPLAYER_FENTER();
5445
5446         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5447
5448         /* check current state */
5449         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5450
5451         /* check pipline building state */
5452         __mmplayer_check_pipeline(player);
5453         __mmplayer_reset_gapless_state(player);
5454
5455         /* NOTE : application should not wait for EOS after calling STOP */
5456         _mmplayer_cancel_eos_timer(player);
5457
5458         /* reset */
5459         player->seek_state = MMPLAYER_SEEK_NONE;
5460
5461         /* stop pipeline */
5462         ret = _mmplayer_gst_stop(player);
5463
5464         if (ret != MM_ERROR_NONE)
5465                 LOGE("failed to stop player.");
5466
5467         MMPLAYER_FLEAVE();
5468
5469         return ret;
5470 }
5471
5472 int
5473 _mmplayer_pause(MMHandleType hplayer)
5474 {
5475         mmplayer_t *player = (mmplayer_t *)hplayer;
5476         gint64 pos_nsec = 0;
5477         gboolean async = FALSE;
5478         gint ret = MM_ERROR_NONE;
5479
5480         MMPLAYER_FENTER();
5481
5482         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5483
5484         /* check current state */
5485         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5486
5487         /* check pipline building state */
5488         __mmplayer_check_pipeline(player);
5489
5490         switch (MMPLAYER_CURRENT_STATE(player)) {
5491         case MM_PLAYER_STATE_READY:
5492                 {
5493                         /* check prepare async or not.
5494                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5495                          */
5496                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5497                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5498
5499                         /* Changing back sync of rtspsrc to async */
5500                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5501                                 LOGD("async prepare working mode for rtsp");
5502                                 async = TRUE;
5503                         }
5504                 }
5505                 break;
5506
5507         case MM_PLAYER_STATE_PLAYING:
5508                 {
5509                         /* NOTE : store current point to overcome some bad operation
5510                         *(returning zero when getting current position in paused state) of some
5511                         * elements
5512                         */
5513                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5514                                 LOGW("getting current position failed in paused");
5515
5516                         player->last_position = pos_nsec;
5517
5518                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5519                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5520                            This causes problem is position calculation during normal pause resume scenarios also.
5521                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5522                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5523                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5524                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5525                         }
5526                 }
5527                 break;
5528         }
5529
5530         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5531                 LOGD("doing async pause in case of ms buff src");
5532                 async = TRUE;
5533         }
5534
5535         /* pause pipeline */
5536         ret = _mmplayer_gst_pause(player, async);
5537
5538         if (ret != MM_ERROR_NONE)
5539                 LOGE("failed to pause player. ret : 0x%x", ret);
5540
5541         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5542                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5543                         LOGE("failed to update display_rotation");
5544         }
5545
5546         MMPLAYER_FLEAVE();
5547
5548         return ret;
5549 }
5550
5551 /* in case of streaming, pause could take long time.*/
5552 int
5553 _mmplayer_abort_pause(MMHandleType hplayer)
5554 {
5555         mmplayer_t *player = (mmplayer_t *)hplayer;
5556         int ret = MM_ERROR_NONE;
5557
5558         MMPLAYER_FENTER();
5559
5560         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5561                                                 player->pipeline &&
5562                                                 player->pipeline->mainbin,
5563                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5564
5565         LOGD("set the pipeline state to READY");
5566
5567         /* set state to READY */
5568         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5569                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5570         if (ret != MM_ERROR_NONE) {
5571                 LOGE("fail to change state to READY");
5572                 return MM_ERROR_PLAYER_INTERNAL;
5573         }
5574
5575         LOGD("succeeded in changing state to READY");
5576         return ret;
5577 }
5578
5579 int
5580 _mmplayer_resume(MMHandleType hplayer)
5581 {
5582         mmplayer_t *player = (mmplayer_t *)hplayer;
5583         int ret = MM_ERROR_NONE;
5584         gboolean async = FALSE;
5585
5586         MMPLAYER_FENTER();
5587
5588         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5589
5590         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5591                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5592                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5593                         return ret;
5594                 }
5595
5596                 /* Changing back sync mode rtspsrc to async */
5597                 LOGD("async resume for rtsp case");
5598                 async = TRUE;
5599         }
5600
5601         /* check current state */
5602         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5603
5604         ret = _mmplayer_gst_resume(player, async);
5605         if (ret != MM_ERROR_NONE)
5606                 LOGE("failed to resume player.");
5607
5608         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5609                 LOGD("force resume even during buffering");
5610                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5611         }
5612
5613         MMPLAYER_FLEAVE();
5614
5615         return ret;
5616 }
5617
5618 int
5619 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5620 {
5621         mmplayer_t *player = (mmplayer_t *)hplayer;
5622         gint64 pos_nsec = 0;
5623         int ret = MM_ERROR_NONE;
5624         bool mute = false;
5625         signed long long start = 0, stop = 0;
5626         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5627         MMPLAYER_FENTER();
5628
5629         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5630         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5631
5632         /* The sound of video is not supported under 0.0 and over 2.0. */
5633         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5634                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5635                         mute = true;
5636         }
5637         _mmplayer_set_mute(hplayer, mute);
5638
5639         if (player->playback_rate == rate)
5640                 return MM_ERROR_NONE;
5641
5642         /* If the position is reached at start potion during fast backward, EOS is posted.
5643          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5644          */
5645         player->playback_rate = rate;
5646
5647         current_state = MMPLAYER_CURRENT_STATE(player);
5648
5649         if (current_state != MM_PLAYER_STATE_PAUSED)
5650                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5651
5652         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5653
5654         if ((current_state == MM_PLAYER_STATE_PAUSED)
5655                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5656                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5657                 pos_nsec = player->last_position;
5658         }
5659
5660         if (rate >= 0) {
5661                 start = pos_nsec;
5662                 stop = GST_CLOCK_TIME_NONE;
5663         } else {
5664                 start = GST_CLOCK_TIME_NONE;
5665                 stop = pos_nsec;
5666         }
5667
5668         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5669                                 player->playback_rate,
5670                                 GST_FORMAT_TIME,
5671                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5672                                 GST_SEEK_TYPE_SET, start,
5673                                 GST_SEEK_TYPE_SET, stop)) {
5674                 LOGE("failed to set speed playback");
5675                 return MM_ERROR_PLAYER_SEEK;
5676         }
5677
5678         LOGD("succeeded to set speed playback as %0.1f", rate);
5679
5680         MMPLAYER_FLEAVE();
5681
5682         return MM_ERROR_NONE;;
5683 }
5684
5685 int
5686 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5687 {
5688         mmplayer_t *player = (mmplayer_t *)hplayer;
5689         int ret = MM_ERROR_NONE;
5690
5691         MMPLAYER_FENTER();
5692
5693         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5694
5695         /* check pipline building state */
5696         __mmplayer_check_pipeline(player);
5697
5698         ret = _mmplayer_gst_set_position(player, position, FALSE);
5699
5700         MMPLAYER_FLEAVE();
5701
5702         return ret;
5703 }
5704
5705 int
5706 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5707 {
5708         mmplayer_t *player = (mmplayer_t *)hplayer;
5709         int ret = MM_ERROR_NONE;
5710
5711         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5713
5714         if (g_strrstr(player->type, "video/mpegts"))
5715                 __mmplayer_update_duration_value(player);
5716
5717         *duration = player->duration;
5718         return ret;
5719 }
5720
5721 int
5722 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5723 {
5724         mmplayer_t *player = (mmplayer_t *)hplayer;
5725         int ret = MM_ERROR_NONE;
5726
5727         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5728
5729         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5730
5731         return ret;
5732 }
5733
5734 int
5735 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5736 {
5737         mmplayer_t *player = (mmplayer_t *)hplayer;
5738         int ret = MM_ERROR_NONE;
5739
5740         MMPLAYER_FENTER();
5741
5742         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5743
5744         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5745
5746         MMPLAYER_FLEAVE();
5747
5748         return ret;
5749 }
5750
5751 static gboolean
5752 __mmplayer_is_midi_type(gchar *str_caps)
5753 {
5754         if ((g_strrstr(str_caps, "audio/midi")) ||
5755                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5756                 (g_strrstr(str_caps, "application/x-smaf")) ||
5757                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5758                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5759                 (g_strrstr(str_caps, "audio/xmf")) ||
5760                 (g_strrstr(str_caps, "audio/mxmf"))) {
5761                 LOGD("midi");
5762                 return TRUE;
5763         }
5764
5765         return FALSE;
5766 }
5767
5768 static gboolean
5769 __mmplayer_is_only_mp3_type(gchar *str_caps)
5770 {
5771         if (g_strrstr(str_caps, "application/x-id3") ||
5772                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5773                 return TRUE;
5774         return FALSE;
5775 }
5776
5777 static void
5778 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5779 {
5780         GstStructure *caps_structure = NULL;
5781         gint samplerate = 0;
5782         gint channels = 0;
5783
5784         MMPLAYER_FENTER();
5785         MMPLAYER_RETURN_IF_FAIL(player && caps);
5786
5787         caps_structure = gst_caps_get_structure(caps, 0);
5788
5789         /* set stream information */
5790         gst_structure_get_int(caps_structure, "rate", &samplerate);
5791         gst_structure_get_int(caps_structure, "channels", &channels);
5792
5793         mm_player_set_attribute((MMHandleType)player, NULL,
5794                         "content_audio_samplerate", samplerate,
5795                         "content_audio_channels", channels, NULL);
5796
5797         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5798 }
5799
5800 static void
5801 __mmplayer_update_content_type_info(mmplayer_t *player)
5802 {
5803         MMPLAYER_FENTER();
5804         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5805
5806         if (__mmplayer_is_midi_type(player->type)) {
5807                 player->bypass_audio_effect = TRUE;
5808                 return;
5809         }
5810
5811         if (!player->streamer) {
5812                 LOGD("no need to check streaming type");
5813                 return;
5814         }
5815
5816         if (g_strrstr(player->type, "application/x-hls")) {
5817                 /* If it can't know exact type when it parses uri because of redirection case,
5818                  * it will be fixed by typefinder or when doing autoplugging.
5819                  */
5820                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5821                 player->streamer->is_adaptive_streaming = TRUE;
5822         } else if (g_strrstr(player->type, "application/dash+xml")) {
5823                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5824                 player->streamer->is_adaptive_streaming = TRUE;
5825         }
5826
5827         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5828         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5829                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5830
5831                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5832                         if (player->streamer->is_adaptive_streaming)
5833                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5834                         else
5835                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5836                 }
5837         }
5838
5839         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5840         MMPLAYER_FLEAVE();
5841 }
5842
5843 void
5844 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5845         GstCaps *caps, gpointer data)
5846 {
5847         mmplayer_t *player = (mmplayer_t *)data;
5848         GstPad *pad = NULL;
5849
5850         MMPLAYER_FENTER();
5851
5852         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5853
5854         /* store type string */
5855         MMPLAYER_FREEIF(player->type);
5856         player->type = gst_caps_to_string(caps);
5857         if (player->type)
5858                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5859                                 player, player->type, probability, gst_caps_get_size(caps));
5860
5861         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5862                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5863                 LOGE("not support media format");
5864
5865                 if (player->msg_posted == FALSE) {
5866                         MMMessageParamType msg_param;
5867                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5868
5869                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5870                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5871
5872                         /* don't post more if one was sent already */
5873                         player->msg_posted = TRUE;
5874                 }
5875                 return;
5876         }
5877
5878         __mmplayer_update_content_type_info(player);
5879
5880         pad = gst_element_get_static_pad(tf, "src");
5881         if (!pad) {
5882                 LOGE("fail to get typefind src pad.");
5883                 return;
5884         }
5885
5886         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5887                 gboolean async = FALSE;
5888                 LOGE("failed to autoplug %s", player->type);
5889
5890                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5891
5892                 if (async && player->msg_posted == FALSE)
5893                         __mmplayer_handle_missed_plugin(player);
5894
5895         }
5896
5897         gst_object_unref(GST_OBJECT(pad));
5898
5899         MMPLAYER_FLEAVE();
5900
5901         return;
5902 }
5903
5904 GstElement *
5905 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5906 {
5907         GstElement *decodebin = NULL;
5908
5909         MMPLAYER_FENTER();
5910
5911         /* create decodebin */
5912         decodebin = gst_element_factory_make("decodebin", NULL);
5913
5914         if (!decodebin) {
5915                 LOGE("fail to create decodebin");
5916                 goto ERROR;
5917         }
5918
5919         /* raw pad handling signal */
5920         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5921                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5922
5923         /* no-more-pad pad handling signal */
5924         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5925                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5926
5927         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5928                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5929
5930         /* This signal is emitted when a pad for which there is no further possible
5931            decoding is added to the decodebin.*/
5932         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5933                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5934
5935         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5936            before looking for any elements that can handle that stream.*/
5937         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5938                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5939
5940         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5941            before looking for any elements that can handle that stream.*/
5942         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5943                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5944
5945         /* This signal is emitted once decodebin has finished decoding all the data.*/
5946         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5947                                                 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5948
5949         /* This signal is emitted when a element is added to the bin.*/
5950         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5951                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5952
5953 ERROR:
5954         return decodebin;
5955 }
5956
5957 static GstElement *
5958 __mmplayer_gst_make_queue2(mmplayer_t *player)
5959 {
5960         GstElement *queue2 = NULL;
5961         gint64 dur_bytes = 0L;
5962         mmplayer_gst_element_t *mainbin = NULL;
5963         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5964
5965         MMPLAYER_FENTER();
5966         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5967
5968         mainbin = player->pipeline->mainbin;
5969
5970         queue2 = gst_element_factory_make("queue2", "queue2");
5971         if (!queue2) {
5972                 LOGE("failed to create buffering queue element");
5973                 return NULL;
5974         }
5975
5976         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5977                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5978
5979         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5980
5981         /* NOTE : in case of ts streaming, player could not get the correct duration info *
5982          *                skip the pull mode(file or ring buffering) setting. */
5983         if (dur_bytes > 0) {
5984                 if (!g_strrstr(player->type, "video/mpegts")) {
5985                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5986                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5987                 }
5988         } else {
5989                 dur_bytes = 0;
5990         }
5991
5992         _mm_player_streaming_set_queue2(player->streamer,
5993                                                                         queue2,
5994                                                                         FALSE,
5995                                                                         type,
5996                                                                         (guint64)dur_bytes); /* no meaning at the moment */
5997
5998         return queue2;
5999 }
6000
6001 gboolean
6002 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6003 {
6004         mmplayer_gst_element_t *mainbin = NULL;
6005         GstElement *decodebin = NULL;
6006         GstElement *queue2 = NULL;
6007         GstPad *sinkpad = NULL;
6008         GstPad *qsrcpad = NULL;
6009
6010         MMPLAYER_FENTER();
6011         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6012
6013         mainbin = player->pipeline->mainbin;
6014
6015         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6016
6017                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6018                         LOGW("need to check: muxed buffer is not null");
6019                 }
6020
6021                 queue2 = __mmplayer_gst_make_queue2(player);
6022                 if (!queue2) {
6023                         LOGE("failed to make queue2");
6024                         goto ERROR;
6025                 }
6026
6027                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6028                         LOGE("failed to add buffering queue");
6029                         goto ERROR;
6030                 }
6031
6032                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6033                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6034
6035                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6036                         LOGE("failed to link [%s:%s]-[%s:%s]",
6037                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6038                         goto ERROR;
6039                 }
6040
6041                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6042                         LOGE("failed to sync queue2 state with parent");
6043                         goto ERROR;
6044                 }
6045
6046                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6047                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6048
6049                 srcpad = qsrcpad;
6050
6051                 gst_object_unref(GST_OBJECT(sinkpad));
6052                 sinkpad = NULL;
6053         }
6054
6055         /* create decodebin */
6056         decodebin = _mmplayer_gst_make_decodebin(player);
6057         if (!decodebin) {
6058                 LOGE("failed to make decodebin");
6059                 goto ERROR;
6060         }
6061
6062         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6063                 LOGE("failed to add decodebin");
6064                 goto ERROR;
6065         }
6066
6067         /* to force caps on the decodebin element and avoid reparsing stuff by
6068         * typefind. It also avoids a deadlock in the way typefind activates pads in
6069         * the state change */
6070         g_object_set(decodebin, "sink-caps", caps, NULL);
6071
6072         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6073
6074         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6075                 LOGE("failed to link [%s:%s]-[%s:%s]",
6076                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6077                 goto ERROR;
6078         }
6079
6080         gst_object_unref(GST_OBJECT(sinkpad));
6081         sinkpad = NULL;
6082         gst_object_unref(GST_OBJECT(qsrcpad));
6083         qsrcpad = NULL;
6084
6085         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6086         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6087
6088         /* set decodebin property about buffer in streaming playback. *
6089          * in case of HLS/DASH, it does not need to have big buffer   *
6090          * because it is kind of adaptive streaming.                  */
6091         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6092                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6093                 gint high_percent = 0;
6094
6095                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6096                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6097
6098                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6099
6100                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6101
6102                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6103                                                                                         "high-percent", high_percent,
6104                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6105                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6106                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6107         }
6108
6109         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6110                 LOGE("failed to sync decodebin state with parent");
6111                 goto ERROR;
6112         }
6113
6114         MMPLAYER_FLEAVE();
6115
6116         return TRUE;
6117
6118 ERROR:
6119
6120         if (sinkpad)
6121                 gst_object_unref(GST_OBJECT(sinkpad));
6122
6123         if (qsrcpad)
6124                 gst_object_unref(GST_OBJECT(qsrcpad));
6125
6126         if (queue2) {
6127                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6128                  * You need to explicitly set elements to the NULL state before
6129                  * dropping the final reference, to allow them to clean up.
6130                  */
6131                 gst_element_set_state(queue2, GST_STATE_NULL);
6132
6133                 /* And, it still has a parent "player".
6134                  * You need to let the parent manage the object instead of unreffing the object directly.
6135                  */
6136                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6137                 gst_object_unref(queue2);
6138                 queue2 = NULL;
6139         }
6140
6141         if (decodebin) {
6142                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6143                  * You need to explicitly set elements to the NULL state before
6144                  * dropping the final reference, to allow them to clean up.
6145                  */
6146                 gst_element_set_state(decodebin, GST_STATE_NULL);
6147
6148                 /* And, it still has a parent "player".
6149                  * You need to let the parent manage the object instead of unreffing the object directly.
6150                  */
6151
6152                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6153                 gst_object_unref(decodebin);
6154                 decodebin = NULL;
6155         }
6156
6157         return FALSE;
6158 }
6159
6160 static int
6161 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6162 {
6163         MMPLAYER_FENTER();
6164
6165         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6166         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6167
6168         LOGD("class : %s, mime : %s", factory_class, mime);
6169
6170         /* add missing plugin */
6171         /* NOTE : msl should check missing plugin for image mime type.
6172          * Some motion jpeg clips can have playable audio track.
6173          * So, msl have to play audio after displaying popup written video format not supported.
6174          */
6175         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6176                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6177                         LOGD("not found demuxer");
6178                         player->not_found_demuxer = TRUE;
6179                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6180
6181                         goto DONE;
6182                 }
6183         }
6184
6185         if (!g_strrstr(factory_class, "Demuxer")) {
6186                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6187                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6188                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6189
6190                         /* check that clip have multi tracks or not */
6191                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6192                                 LOGD("video plugin is already linked");
6193                         } else {
6194                                 LOGW("add VIDEO to missing plugin");
6195                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6196                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6197                         }
6198                 } else if (g_str_has_prefix(mime, "audio")) {
6199                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6200                                 LOGD("audio plugin is already linked");
6201                         } else {
6202                                 LOGW("add AUDIO to missing plugin");
6203                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6204                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6205                         }
6206                 }
6207         }
6208
6209 DONE:
6210         MMPLAYER_FLEAVE();
6211
6212         return MM_ERROR_NONE;
6213 }
6214
6215 static void
6216 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
6217 {
6218         mmplayer_t *player = (mmplayer_t *)data;
6219
6220         MMPLAYER_FENTER();
6221
6222         MMPLAYER_RETURN_IF_FAIL(player);
6223
6224         /* remove fakesink. */
6225         if (!_mmplayer_gst_remove_fakesink(player,
6226                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6227                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6228                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6229                  * source element are not same. To overcome this situation, this function will called
6230                  * several places and several times. Therefore, this is not an error case.
6231                  */
6232                 return;
6233         }
6234
6235         LOGD("[handle: %p] pipeline has completely constructed", player);
6236
6237         if ((player->ini.async_start) &&
6238                 (player->msg_posted == FALSE) &&
6239                 (player->cmd >= MMPLAYER_COMMAND_START))
6240                 __mmplayer_handle_missed_plugin(player);
6241
6242         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6243 }
6244
6245 static int
6246 __mmplayer_check_profile(void)
6247 {
6248         char *profileName;
6249         static int profile_tv = -1;
6250
6251         if (__builtin_expect(profile_tv != -1, 1))
6252                 return profile_tv;
6253
6254         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6255         switch (*profileName) {
6256         case 't':
6257         case 'T':
6258                 profile_tv = 1;
6259                 break;
6260         default:
6261                 profile_tv = 0;
6262                 break;
6263         }
6264         free(profileName);
6265
6266         return profile_tv;
6267 }
6268
6269 static gboolean
6270 __mmplayer_get_next_uri(mmplayer_t *player)
6271 {
6272         mmplayer_parse_profile_t profile;
6273         gint uri_idx = 0;
6274         guint num_of_list = 0;
6275         char *uri = NULL;
6276
6277         num_of_list = g_list_length(player->uri_info.uri_list);
6278         uri_idx = player->uri_info.uri_idx;
6279
6280         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6281         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6282                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6283                 if (!uri) {
6284                         LOGW("next uri does not exist");
6285                         continue;
6286                 }
6287
6288                 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6289                         LOGE("failed to parse profile");
6290                         continue;
6291                 }
6292
6293                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6294                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6295                         LOGW("uri type is not supported(%d)", profile.uri_type);
6296                         continue;
6297                 }
6298
6299                 LOGD("success to find next uri %d", uri_idx);
6300                 break;
6301         }
6302
6303         if (!uri || uri_idx == num_of_list) {
6304                 LOGE("failed to find next uri");
6305                 return FALSE;
6306         }
6307
6308         player->uri_info.uri_idx = uri_idx;
6309         if (mm_player_set_attribute((MMHandleType)player, NULL,
6310                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6311                 LOGE("failed to set attribute");
6312                 return FALSE;
6313         }
6314
6315         SECURE_LOGD("next playback uri: %s", uri);
6316         return TRUE;
6317 }
6318
6319 static gboolean
6320 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6321 {
6322 #define REPEAT_COUNT_INFINITE -1
6323 #define REPEAT_COUNT_MIN 2
6324 #define ORIGINAL_URI_ONLY 1
6325
6326         MMHandleType attrs = 0;
6327         gint video = 0;
6328         gint count = 0;
6329         gint gapless = 0;
6330         guint num_of_uri = 0;
6331         int profile_tv = -1;
6332
6333         MMPLAYER_FENTER();
6334
6335         LOGD("checking for gapless play option");
6336
6337         if (player->build_audio_offload) {
6338                 LOGE("offload path is not supportable.");
6339                 goto ERROR;
6340         }
6341
6342         if (player->pipeline->textbin) {
6343                 LOGE("subtitle path is enabled. gapless play is not supported.");
6344                 goto ERROR;
6345         }
6346
6347         attrs = MMPLAYER_GET_ATTRS(player);
6348         if (!attrs) {
6349                 LOGE("fail to get attributes.");
6350                 goto ERROR;
6351         }
6352
6353         mm_attrs_multiple_get(player->attrs, NULL,
6354                         "content_video_found", &video,
6355                         "profile_play_count", &count,
6356                         MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6357
6358         /* gapless playback is not supported in case of video at TV profile. */
6359         profile_tv = __mmplayer_check_profile();
6360         if (profile_tv && video) {
6361                 LOGW("not support video gapless playback");
6362                 goto ERROR;
6363         }
6364
6365         /* check repeat count in case of audio */
6366         if (!gapless &&
6367                 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6368                 LOGW("gapless is disabled");
6369                 goto ERROR;
6370         }
6371
6372         num_of_uri = g_list_length(player->uri_info.uri_list);
6373
6374         LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6375
6376         if (num_of_uri == ORIGINAL_URI_ONLY) {
6377                 /* audio looping path */
6378                 if (count >= REPEAT_COUNT_MIN) {
6379                         /* decrease play count */
6380                         /* we succeeded to rewind. update play count and then wait for next EOS */
6381                         count--;
6382                         mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6383                 } else if (count != REPEAT_COUNT_INFINITE) {
6384                         LOGD("there is no next uri and no repeat");
6385                         goto ERROR;
6386                 }
6387                 LOGD("looping cnt %d", count);
6388         } else {
6389                 /* gapless playback path */
6390                 if (!__mmplayer_get_next_uri(player)) {
6391                         LOGE("failed to get next uri");
6392                         goto ERROR;
6393                 }
6394         }
6395         return TRUE;
6396
6397 ERROR:
6398         LOGE("unable to play gapless path. EOS will be posted soon");
6399         return FALSE;
6400 }
6401
6402 static gboolean
6403 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6404 {
6405         mmplayer_selector_t *selector = &player->selector[type];
6406         mmplayer_gst_element_t *sinkbin = NULL;
6407         main_element_id_e selectorId = MMPLAYER_M_NUM;
6408         main_element_id_e sinkId = MMPLAYER_M_NUM;
6409         GstPad *srcpad = NULL;
6410         GstPad *sinkpad = NULL;
6411         gboolean send_notice = FALSE;
6412
6413         MMPLAYER_FENTER();
6414         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6415
6416         LOGD("type %d", type);
6417
6418         switch (type) {
6419         case MM_PLAYER_TRACK_TYPE_AUDIO:
6420                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6421                 sinkId = MMPLAYER_A_BIN;
6422                 sinkbin = player->pipeline->audiobin;
6423                 break;
6424         case MM_PLAYER_TRACK_TYPE_VIDEO:
6425                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6426                 sinkId = MMPLAYER_V_BIN;
6427                 sinkbin = player->pipeline->videobin;
6428                 send_notice = TRUE;
6429                 break;
6430         case MM_PLAYER_TRACK_TYPE_TEXT:
6431                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6432                 sinkId = MMPLAYER_T_BIN;
6433                 sinkbin = player->pipeline->textbin;
6434                 break;
6435         default:
6436                 LOGE("requested type is not supportable");
6437                 return FALSE;
6438                 break;
6439         }
6440
6441         if (player->pipeline->mainbin[selectorId].gst) {
6442                 gint n;
6443
6444                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6445
6446                 if (selector->event_probe_id != 0)
6447                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6448                 selector->event_probe_id = 0;
6449
6450                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6451                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6452
6453                         if (srcpad && sinkpad) {
6454                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6455                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6456                                 gst_pad_unlink(srcpad, sinkpad);
6457
6458                                 /* send custom event to sink pad to handle it at video sink */
6459                                 if (send_notice) {
6460                                         LOGD("send custom event to sinkpad");
6461                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6462                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6463                                         gst_pad_send_event(sinkpad, event);
6464                                 }
6465                         }
6466
6467                         gst_object_unref(sinkpad);
6468                         sinkpad = NULL;
6469                 }
6470                 gst_object_unref(srcpad);
6471                 srcpad = NULL;
6472
6473                 LOGD("selector release");
6474
6475                 /* release and unref requests pad from the selector */
6476                 for (n = 0; n < selector->channels->len; n++) {
6477                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6478                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6479                 }
6480                 g_ptr_array_set_size(selector->channels, 0);
6481
6482                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6483                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6484
6485                 player->pipeline->mainbin[selectorId].gst = NULL;
6486                 selector = NULL;
6487         }
6488
6489         return TRUE;
6490 }
6491
6492 static void
6493 __mmplayer_deactivate_old_path(mmplayer_t *player)
6494 {
6495         MMPLAYER_FENTER();
6496         MMPLAYER_RETURN_IF_FAIL(player);
6497
6498         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6499                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6500                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6501                 LOGE("deactivate selector error");
6502                 goto ERROR;
6503         }
6504
6505         _mmplayer_track_destroy(player);
6506         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6507
6508         if (player->streamer) {
6509                 _mm_player_streaming_initialize(player->streamer, FALSE);
6510                 _mm_player_streaming_destroy(player->streamer);
6511                 player->streamer = NULL;
6512         }
6513
6514         MMPLAYER_PLAYBACK_LOCK(player);
6515         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6516
6517         MMPLAYER_FLEAVE();
6518         return;
6519
6520 ERROR:
6521
6522         if (!player->msg_posted) {
6523                 MMMessageParamType msg = {0,};
6524
6525                 /*post error*/
6526                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6527                 LOGE("gapless_uri_play> deactivate error");
6528
6529                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6530                 player->msg_posted = TRUE;
6531         }
6532         return;
6533 }
6534
6535 int
6536 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6537 {
6538         int result = MM_ERROR_NONE;
6539         mmplayer_t *player = (mmplayer_t *)hplayer;
6540         MMPLAYER_FENTER();
6541
6542         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6543         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6544
6545         if (mm_player_set_attribute(hplayer, NULL,
6546                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6547                 LOGE("failed to set attribute");
6548                 result = MM_ERROR_PLAYER_INTERNAL;
6549         } else {
6550                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6551                         LOGE("failed to add the original uri in the uri list.");
6552         }
6553
6554         MMPLAYER_FLEAVE();
6555         return result;
6556 }
6557
6558 int
6559 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6560 {
6561         mmplayer_t *player = (mmplayer_t *)hplayer;
6562         guint num_of_list = 0;
6563
6564         MMPLAYER_FENTER();
6565
6566         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6567         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6568
6569         if (player->pipeline && player->pipeline->textbin) {
6570                 LOGE("subtitle path is enabled.");
6571                 return MM_ERROR_PLAYER_INVALID_STATE;
6572         }
6573
6574         num_of_list = g_list_length(player->uri_info.uri_list);
6575
6576         if (is_first_path) {
6577                 if (num_of_list == 0) {
6578                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6579                         SECURE_LOGD("add original path : %s", uri);
6580                 } else {
6581                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6582                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6583
6584                         SECURE_LOGD("change original path : %s", uri);
6585                 }
6586         } else {
6587                 MMHandleType attrs = 0;
6588                 attrs = MMPLAYER_GET_ATTRS(player);
6589
6590                 if (num_of_list == 0) {
6591                         char *original_uri = NULL;
6592
6593                         if (attrs) {
6594                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6595
6596                                 if (!original_uri) {
6597                                         LOGE("there is no original uri.");
6598                                         return MM_ERROR_PLAYER_INVALID_STATE;
6599                                 }
6600
6601                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6602                                 player->uri_info.uri_idx = 0;
6603
6604                                 SECURE_LOGD("add original path at first : %s", original_uri);
6605                         }
6606                 }
6607
6608                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6609                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6610         }
6611
6612         MMPLAYER_FLEAVE();
6613         return MM_ERROR_NONE;
6614 }
6615
6616 int
6617 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6618 {
6619         mmplayer_t *player = (mmplayer_t *)hplayer;
6620         char *next_uri = NULL;
6621         guint num_of_list = 0;
6622
6623         MMPLAYER_FENTER();
6624         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6625
6626         num_of_list = g_list_length(player->uri_info.uri_list);
6627
6628         if (num_of_list > 0) {
6629                 gint uri_idx = player->uri_info.uri_idx;
6630
6631                 if (uri_idx < num_of_list-1)
6632                         uri_idx++;
6633                 else
6634                         uri_idx = 0;
6635
6636                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6637                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6638
6639                 *uri = g_strdup(next_uri);
6640         }
6641
6642         MMPLAYER_FLEAVE();
6643         return MM_ERROR_NONE;
6644 }
6645
6646 static void
6647 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad *pad,
6648         GstCaps *caps, gpointer data)
6649 {
6650         mmplayer_t *player = (mmplayer_t *)data;
6651         const gchar *klass = NULL;
6652         const gchar *mime = NULL;
6653         gchar *caps_str = NULL;
6654
6655         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6656         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6657         caps_str = gst_caps_to_string(caps);
6658
6659         LOGW("unknown type of caps : %s from %s",
6660                                         caps_str, GST_ELEMENT_NAME(elem));
6661
6662         MMPLAYER_FREEIF(caps_str);
6663
6664         /* There is no available codec. */
6665         __mmplayer_check_not_supported_codec(player, klass, mime);
6666 }
6667
6668 static gboolean
6669 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad,
6670         GstCaps *caps,  gpointer data)
6671 {
6672         mmplayer_t *player = (mmplayer_t *)data;
6673         const char *mime = NULL;
6674         gboolean ret = TRUE;
6675
6676         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6677         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6678
6679         if (g_str_has_prefix(mime, "audio")) {
6680                 GstStructure *caps_structure = NULL;
6681                 gint samplerate = 0;
6682                 gint channels = 0;
6683                 gchar *caps_str = NULL;
6684
6685                 caps_structure = gst_caps_get_structure(caps, 0);
6686                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6687                 gst_structure_get_int(caps_structure, "channels", &channels);
6688
6689                 if ((channels > 0 && samplerate == 0)) {
6690                         LOGD("exclude audio...");
6691                         ret = FALSE;
6692                 }
6693
6694                 caps_str = gst_caps_to_string(caps);
6695                 /* set it directly because not sent by TAG */
6696                 if (g_strrstr(caps_str, "mobile-xmf"))
6697                         mm_player_set_attribute((MMHandleType)player, NULL,
6698                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6699
6700                 MMPLAYER_FREEIF(caps_str);
6701         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6702                 MMMessageParamType msg_param;
6703                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6704                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6705                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6706                 LOGD("video file is not supported on this device");
6707                 ret = FALSE;
6708         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6709                 LOGD("already video linked");
6710                 ret = FALSE;
6711         } else {
6712                 LOGD("found new stream");
6713         }
6714
6715         return ret;
6716 }
6717
6718 static gboolean
6719 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6720 {
6721         gboolean ret = FALSE;
6722         GDBusConnection *conn = NULL;
6723         GError *err = NULL;
6724         GVariant *result = NULL;
6725         const gchar *dbus_device_type = NULL;
6726         const gchar *dbus_ret = NULL;
6727         gint idx = 0;
6728
6729         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6730         if (!conn || err) {
6731                 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6732                 g_error_free(err);
6733                 goto DONE;
6734         }
6735
6736         result = g_dbus_connection_call_sync(conn,
6737                                         "org.pulseaudio.Server",
6738                                         "/org/pulseaudio/StreamManager",
6739                                         "org.pulseaudio.StreamManager",
6740                                         "GetCurrentMediaRoutingPath",
6741                                         g_variant_new("(s)", "out"),
6742                                         G_VARIANT_TYPE("(ss)"),
6743                                         G_DBUS_CALL_FLAGS_NONE,
6744                                         2000,
6745                                         NULL,
6746                                         &err);
6747         if (!result || err) {
6748                 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6749                 g_error_free(err);
6750                 goto DONE;
6751         }
6752
6753         /* device type is listed in stream-map.json at mmfw-sysconf */
6754         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6755
6756         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6757         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6758                 goto DONE;
6759
6760         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6761         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6762                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6763                         LOGD("audio offload is supportable");
6764                         ret = TRUE;
6765                         goto DONE;
6766                 }
6767         }
6768
6769         LOGD("audio offload is not supportable");
6770
6771 DONE:
6772         g_variant_unref(result);
6773         if (conn)
6774                 g_object_unref(conn);
6775
6776         return ret;
6777 }
6778
6779 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6780 {
6781         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6782         gint64 position = 0;
6783
6784         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6785                 player->pipeline && player->pipeline->mainbin);
6786
6787         MMPLAYER_CMD_LOCK(player);
6788         current_state = MMPLAYER_CURRENT_STATE(player);
6789
6790         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6791                 LOGW("getting current position failed in paused");
6792
6793         _mmplayer_unrealize((MMHandleType)player);
6794         _mmplayer_realize((MMHandleType)player);
6795
6796         _mmplayer_set_position((MMHandleType)player, position);
6797
6798         /* async not to be blocked in streaming case */
6799         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6800
6801         _mmplayer_pause((MMHandleType)player);
6802
6803         if (current_state == MM_PLAYER_STATE_PLAYING)
6804                 _mmplayer_start((MMHandleType)player);
6805         MMPLAYER_CMD_UNLOCK(player);
6806
6807         LOGD("rebuilding audio pipeline is completed.");
6808 }
6809
6810 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6811 {
6812         mmplayer_t *player = (mmplayer_t *)user_data;
6813         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6814         gboolean is_supportable = FALSE;
6815
6816         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6817                 LOGW("failed to get device type");
6818         else
6819                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6820
6821         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6822                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6823                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6824                 LOGD("ignore this dev connected info");
6825                 return;
6826         }
6827
6828         is_supportable = __mmplayer_is_audio_offload_device_type(player);
6829         if (player->build_audio_offload == is_supportable) {
6830                 LOGD("keep current pipeline without re-building");
6831                 return;
6832         }
6833
6834         /* rebuild pipeline */
6835         LOGD("re-build pipeline - offload: %d", is_supportable);
6836         player->build_audio_offload = FALSE;
6837         __mmplayer_rebuild_audio_pipeline(player);
6838
6839         return;
6840 }
6841
6842 static gboolean
6843 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6844 {
6845         unsigned int id = 0;
6846
6847         if (player->audio_device_cb_id != 0) {
6848                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6849                 return TRUE;
6850         }
6851
6852         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6853                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6854                 LOGD("added device connected cb (%u)", id);
6855                 player->audio_device_cb_id = id;
6856         } else {
6857                 LOGW("failed to add device connected cb");
6858                 return FALSE;
6859         }
6860
6861         return TRUE;
6862 }
6863
6864 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6865 {
6866         mmplayer_t *player = (mmplayer_t *)hplayer;
6867
6868         MMPLAYER_FENTER();
6869         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6870         MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6871
6872         *activated = player->build_audio_offload;
6873
6874         LOGD("offload activated : %d", (int)*activated);
6875
6876         MMPLAYER_FLEAVE();
6877         return MM_ERROR_NONE;
6878 }
6879
6880 static gboolean
6881 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6882 {
6883         /* NOTE :
6884            this function need to be updated according to the supported media format
6885            @see player->ini.audio_offload_media_format */
6886
6887         if (__mmplayer_is_only_mp3_type(player->type)) {
6888                 LOGD("offload supportable media format type");
6889                 return TRUE;
6890         }
6891
6892         return FALSE;
6893 }
6894
6895 static gboolean
6896 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6897 {
6898         gboolean ret = FALSE;
6899         GstElementFactory *factory = NULL;
6900
6901         MMPLAYER_FENTER();
6902         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6903
6904         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6905         if (!__mmplayer_is_offload_supported_type(player))
6906                 goto DONE;
6907
6908         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6909                 LOGD("there is no audio offload sink");
6910                 goto DONE;
6911         }
6912
6913         if (player->ini.audio_offload_device_type[0][0] == '\0') {
6914                 LOGW("there is no audio device type to support offload");
6915                 goto DONE;
6916         }
6917
6918         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6919         if (!factory) {
6920                 LOGW("there is no installed audio offload sink element");
6921                 goto DONE;
6922         }
6923         gst_object_unref(factory);
6924
6925         if (__mmplayer_acquire_hw_resource(player,
6926                         MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6927                 LOGE("failed to acquire audio offload decoder resource");
6928                 goto DONE;
6929         }
6930
6931         if (!__mmplayer_add_audio_device_connected_cb(player))
6932                 goto DONE;
6933
6934         if (!__mmplayer_is_audio_offload_device_type(player))
6935                 goto DONE;
6936
6937         LOGD("audio offload can be built");
6938         ret = TRUE;
6939
6940 DONE:
6941         if (!ret)
6942                 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6943
6944         MMPLAYER_FLEAVE();
6945         return ret;
6946 }
6947
6948 static GstAutoplugSelectResult
6949 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6950 {
6951         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6952         int idx = 0;
6953         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6954         int audio_offload = 0;
6955
6956         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6957                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6958
6959                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6960                         LOGD("expose audio path to build offload output path");
6961                         player->build_audio_offload = TRUE;
6962                         /* update codec info */
6963                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6964                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6965                         player->audiodec_linked = 1;
6966
6967                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
6968                         goto DONE;
6969                 }
6970
6971                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6972
6973                 LOGD("audio codec type: %d", codec_type);
6974                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6975                         /* sw codec will be skipped */
6976                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6977                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6978                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6979                                         ret = GST_AUTOPLUG_SELECT_SKIP;
6980                                         goto DONE;
6981                                 }
6982                         }
6983                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6984                         /* hw codec will be skipped */
6985                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
6986                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6987                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6988                                 ret = GST_AUTOPLUG_SELECT_SKIP;
6989                                 goto DONE;
6990                         }
6991                 }
6992
6993                 /* set stream information */
6994                 if (!player->audiodec_linked)
6995                         __mmplayer_set_audio_attrs(player, caps);
6996
6997                 /* update codec info */
6998                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6999                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7000                 player->audiodec_linked = 1;
7001
7002         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7003
7004                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7005
7006                 LOGD("video codec type: %d", codec_type);
7007                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7008                         /* sw codec is skipped */
7009                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7010                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7011                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7012                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7013                                         goto DONE;
7014                                 }
7015                         }
7016                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7017                         /* hw codec is skipped */
7018                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7019                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7020                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7021                                 goto DONE;
7022                         }
7023                 }
7024
7025                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7026                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7027
7028                         /* mark video decoder for acquire */
7029                         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7030                                 LOGW("video decoder resource is already acquired, skip it.");
7031                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7032                                 goto DONE;
7033                         }
7034
7035                         if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7036                                 LOGE("failed to acquire video decoder resource");
7037                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7038                                 goto DONE;
7039                         }
7040                         player->interrupted_by_resource = FALSE;
7041                 }
7042
7043                 /* update codec info */
7044                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7045                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7046                 player->videodec_linked = 1;
7047         }
7048
7049 DONE:
7050         return ret;
7051 }
7052
7053 gint
7054 _mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7055         GstCaps *caps, GstElementFactory *factory, gpointer data)
7056 {
7057         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7058         mmplayer_t *player = (mmplayer_t *)data;
7059
7060         gchar *factory_name = NULL;
7061         gchar *caps_str = NULL;
7062         const gchar *klass = NULL;
7063         gint idx = 0;
7064
7065         factory_name = GST_OBJECT_NAME(factory);
7066         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7067         caps_str = gst_caps_to_string(caps);
7068
7069         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7070
7071         /* store type string */
7072         if (player->type == NULL) {
7073                 player->type = gst_caps_to_string(caps);
7074                 __mmplayer_update_content_type_info(player);
7075         }
7076
7077         /* filtering exclude keyword */
7078         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7079                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7080                         LOGW("skipping [%s] by exculde keyword [%s]",
7081                                         factory_name, player->ini.exclude_element_keyword[idx]);
7082
7083                         result = GST_AUTOPLUG_SELECT_SKIP;
7084                         goto DONE;
7085                 }
7086         }
7087
7088         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7089                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7090                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7091                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7092                         result = GST_AUTOPLUG_SELECT_SKIP;
7093                         goto DONE;
7094                 }
7095         }
7096
7097         /* exclude webm format */
7098         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7099          * because webm format is not supportable.
7100          * If webm is disabled in "autoplug-continue", there is no state change
7101          * failure or error because the decodebin will expose the pad directly.
7102          * It make MSL invoke _prepare_async_callback.
7103          * So, we need to disable webm format in "autoplug-select" */
7104         if (caps_str && strstr(caps_str, "webm")) {
7105                 LOGW("webm is not supported");
7106                 result = GST_AUTOPLUG_SELECT_SKIP;
7107                 goto DONE;
7108         }
7109
7110         /* check factory class for filtering */
7111         /* NOTE : msl don't need to use image plugins.
7112          * So, those plugins should be skipped for error handling.
7113          */
7114         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7115                 LOGD("skipping [%s] by not required", factory_name);
7116                 result = GST_AUTOPLUG_SELECT_SKIP;
7117                 goto DONE;
7118         }
7119
7120         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7121                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7122                 // TO CHECK : subtitle if needed, add subparse exception.
7123                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7124                 result = GST_AUTOPLUG_SELECT_SKIP;
7125                 goto DONE;
7126         }
7127
7128         if (g_strrstr(factory_name, "mpegpsdemux")) {
7129                 LOGD("skipping PS container - not support");
7130                 result = GST_AUTOPLUG_SELECT_SKIP;
7131                 goto DONE;
7132         }
7133
7134         if (g_strrstr(factory_name, "mssdemux"))
7135                 player->smooth_streaming = TRUE;
7136
7137         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7138                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7139                 gint stype = 0;
7140                 gint width = 0;
7141                 GstStructure *str = NULL;
7142                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7143
7144                 /* don't make video because of not required */
7145                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7146                         (!player->set_mode.video_export)) {
7147                         LOGD("no need video decoding, expose pad");
7148                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7149                         goto DONE;
7150                 }
7151
7152                 /* get w/h for omx state-tune */
7153                 /* FIXME: deprecated? */
7154                 str = gst_caps_get_structure(caps, 0);
7155                 gst_structure_get_int(str, "width", &width);
7156
7157                 if (width != 0) {
7158                         if (player->v_stream_caps) {
7159                                 gst_caps_unref(player->v_stream_caps);
7160                                 player->v_stream_caps = NULL;
7161                         }
7162
7163                         player->v_stream_caps = gst_caps_copy(caps);
7164                         LOGD("take caps for video state tune");
7165                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7166                 }
7167         }
7168
7169         if (g_strrstr(klass, "Codec/Decoder")) {
7170                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7171                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7172                         LOGW("skip add decoder");
7173                         goto DONE;
7174                 }
7175         }
7176
7177 DONE:
7178         MMPLAYER_FREEIF(caps_str);
7179
7180         return result;
7181 }
7182
7183 static void
7184 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad *new_pad,
7185         gpointer data)
7186 {
7187         //mmplayer_t *player = (mmplayer_t *)data;
7188         GstCaps *caps = NULL;
7189
7190         LOGD("[Decodebin2] pad-removed signal");
7191
7192         caps = gst_pad_query_caps(new_pad, NULL);
7193         if (!caps) {
7194                 LOGW("query caps is NULL");
7195                 return;
7196         }
7197
7198         gchar *caps_str = NULL;
7199         caps_str = gst_caps_to_string(caps);
7200
7201         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7202
7203         MMPLAYER_FREEIF(caps_str);
7204         gst_caps_unref(caps);
7205 }
7206
7207 static void
7208 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7209 {
7210         mmplayer_t *player = (mmplayer_t *)data;
7211         GstIterator *iter = NULL;
7212         GValue item = { 0, };
7213         GstPad *pad = NULL;
7214         gboolean done = FALSE;
7215         gboolean is_all_drained = TRUE;
7216
7217         MMPLAYER_FENTER();
7218         MMPLAYER_RETURN_IF_FAIL(player);
7219
7220         LOGD("__mmplayer_gst_decode_drained");
7221
7222         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7223                 LOGW("Fail to get cmd lock");
7224                 return;
7225         }
7226
7227         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7228                 !__mmplayer_verify_gapless_play_path(player)) {
7229                 LOGD("decoding is finished.");
7230                 __mmplayer_reset_gapless_state(player);
7231                 MMPLAYER_CMD_UNLOCK(player);
7232                 return;
7233         }
7234
7235         player->gapless.reconfigure = TRUE;
7236
7237         /* check decodebin src pads whether they received EOS or not */
7238         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7239
7240         while (!done) {
7241                 switch (gst_iterator_next(iter, &item)) {
7242                 case GST_ITERATOR_OK:
7243                         pad = g_value_get_object(&item);
7244                         if (pad && !GST_PAD_IS_EOS(pad)) {
7245                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7246                                 is_all_drained = FALSE;
7247                                 break;
7248                         }
7249                         g_value_reset(&item);
7250                         break;
7251                 case GST_ITERATOR_RESYNC:
7252                         gst_iterator_resync(iter);
7253                         break;
7254                 case GST_ITERATOR_ERROR:
7255                 case GST_ITERATOR_DONE:
7256                         done = TRUE;
7257                         break;
7258                 }
7259         }
7260         g_value_unset(&item);
7261         gst_iterator_free(iter);
7262
7263         if (!is_all_drained) {
7264                 LOGD("Wait util the all pads get EOS.");
7265                 MMPLAYER_CMD_UNLOCK(player);
7266                 MMPLAYER_FLEAVE();
7267                 return;
7268         }
7269
7270         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7271         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7272
7273         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7274         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7275         __mmplayer_deactivate_old_path(player);
7276         MMPLAYER_CMD_UNLOCK(player);
7277
7278         MMPLAYER_FLEAVE();
7279 }
7280
7281 void
7282 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7283 {
7284         mmplayer_t *player = (mmplayer_t *)data;
7285         const gchar *klass = NULL;
7286         gchar *factory_name = NULL;
7287
7288         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7289         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7290
7291         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7292
7293         if (__mmplayer_add_dump_buffer_probe(player, element))
7294                 LOGD("add buffer probe");
7295
7296         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7297                 gchar *selected = NULL;
7298                 selected = g_strdup(GST_ELEMENT_NAME(element));
7299                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7300         }
7301
7302         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7303                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7304                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7305
7306                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7307                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7308
7309                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7310                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7311                                                 "max-video-width", player->adaptive_info.limit.width,
7312                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7313
7314         } else if (g_strrstr(klass, "Demuxer")) {
7315 #ifdef __DEBUG__
7316                 LOGD("plugged element is demuxer. take it");
7317 #endif
7318                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7319                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7320         }
7321
7322         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7323                 int surface_type = 0;
7324
7325                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7326         }
7327
7328         // to support trust-zone only
7329         if (g_strrstr(factory_name, "asfdemux")) {
7330                 LOGD("set file-location %s", player->profile.uri);
7331                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7332         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7333                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7334                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7335         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7336                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7337                         (__mmplayer_is_only_mp3_type(player->type))) {
7338                         LOGD("[mpegaudioparse] set streaming pull mode.");
7339                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7340                 }
7341         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7342                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7343         }
7344
7345         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7346                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7347                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7348
7349                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7350                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7351
7352                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7353                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7354                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7355                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7356                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7357                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7358                 }
7359
7360         }
7361
7362         return;
7363 }
7364
7365 static void
7366 __mmplayer_release_misc(mmplayer_t *player)
7367 {
7368         int i;
7369         bool cur_mode = player->set_mode.rich_audio;
7370         MMPLAYER_FENTER();
7371
7372         MMPLAYER_RETURN_IF_FAIL(player);
7373
7374         player->video_decoded_cb = NULL;
7375         player->video_decoded_cb_user_param = NULL;
7376         player->video_stream_prerolled = false;
7377
7378         player->audio_decoded_cb = NULL;
7379         player->audio_decoded_cb_user_param = NULL;
7380         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7381
7382         player->audio_stream_changed_cb = NULL;
7383         player->audio_stream_changed_cb_user_param = NULL;
7384
7385         player->sent_bos = FALSE;
7386         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7387
7388         player->seek_state = MMPLAYER_SEEK_NONE;
7389
7390         player->total_bitrate = 0;
7391         player->total_maximum_bitrate = 0;
7392
7393         player->not_found_demuxer = 0;
7394
7395         player->last_position = 0;
7396         player->duration = 0;
7397         player->http_content_size = 0;
7398         player->not_supported_codec = MISSING_PLUGIN_NONE;
7399         player->can_support_codec = FOUND_PLUGIN_NONE;
7400         player->pending_seek.is_pending = false;
7401         player->pending_seek.pos = 0;
7402         player->msg_posted = FALSE;
7403         player->has_many_types = FALSE;
7404         player->is_subtitle_force_drop = FALSE;
7405         player->play_subtitle = FALSE;
7406         player->adjust_subtitle_pos = 0;
7407         player->has_closed_caption = FALSE;
7408         player->set_mode.video_export = false;
7409         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7410         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7411         /* recover mode */
7412         player->set_mode.rich_audio = cur_mode;
7413
7414         if (player->audio_device_cb_id > 0 &&
7415                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7416                 LOGW("failed to remove audio device_connected_callback");
7417         player->audio_device_cb_id = 0;
7418
7419         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7420                 player->bitrate[i] = 0;
7421                 player->maximum_bitrate[i] = 0;
7422         }
7423
7424         /* free memory related to audio effect */
7425         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7426
7427         if (player->adaptive_info.var_list) {
7428                 g_list_free_full(player->adaptive_info.var_list, g_free);
7429                 player->adaptive_info.var_list = NULL;
7430         }
7431
7432         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7433         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7434         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7435
7436         /* Reset video360 settings to their defaults in case if the pipeline is to be
7437          * re-created.
7438          * */
7439         player->video360_metadata.is_spherical = -1;
7440         player->is_openal_plugin_used = FALSE;
7441
7442         player->is_content_spherical = FALSE;
7443         player->is_video360_enabled = TRUE;
7444         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7445         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7446         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7447         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7448         player->video360_zoom = 1.0f;
7449         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7450         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7451
7452         player->sound.rg_enable = false;
7453
7454         __mmplayer_initialize_video_roi(player);
7455         MMPLAYER_FLEAVE();
7456 }
7457
7458 static void
7459 __mmplayer_release_misc_post(mmplayer_t *player)
7460 {
7461         char *original_uri = NULL;
7462         MMPLAYER_FENTER();
7463
7464         /* player->pipeline is already released before. */
7465
7466         MMPLAYER_RETURN_IF_FAIL(player);
7467
7468         mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7469
7470         /* clean found audio decoders */
7471         if (player->audio_decoders) {
7472                 GList *a_dec = player->audio_decoders;
7473                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7474                         gchar *name = a_dec->data;
7475                         MMPLAYER_FREEIF(name);
7476                 }
7477                 g_list_free(player->audio_decoders);
7478                 player->audio_decoders = NULL;
7479         }
7480
7481         /* clean the uri list except original uri */
7482         if (player->uri_info.uri_list) {
7483                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7484
7485                 if (!original_uri)
7486                         LOGW("failed to get original uri info");
7487
7488                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7489                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7490
7491                 GList *uri_list = player->uri_info.uri_list;
7492                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7493                         gchar *uri = uri_list->data;
7494                         MMPLAYER_FREEIF(uri);
7495                 }
7496                 g_list_free(player->uri_info.uri_list);
7497                 player->uri_info.uri_list = NULL;
7498         }
7499
7500         /* clear the audio stream buffer list */
7501         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7502
7503         /* clear the video stream bo list */
7504         __mmplayer_video_stream_destroy_bo_list(player);
7505         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7506
7507         if (player->profile.input_mem.buf) {
7508                 free(player->profile.input_mem.buf);
7509                 player->profile.input_mem.buf = NULL;
7510         }
7511         player->profile.input_mem.len = 0;
7512         player->profile.input_mem.offset = 0;
7513
7514         player->uri_info.uri_idx = 0;
7515         MMPLAYER_FLEAVE();
7516 }
7517
7518 gboolean
7519 __mmplayer_check_subtitle(mmplayer_t *player)
7520 {
7521         MMHandleType attrs = 0;
7522         char *subtitle_uri = NULL;
7523
7524         MMPLAYER_FENTER();
7525
7526         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7527
7528         /* get subtitle attribute */
7529         attrs = MMPLAYER_GET_ATTRS(player);
7530         if (!attrs)
7531                 return FALSE;
7532
7533         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7534         if (!subtitle_uri || !strlen(subtitle_uri))
7535                 return FALSE;
7536
7537         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7538         player->is_external_subtitle_present = TRUE;
7539
7540         MMPLAYER_FLEAVE();
7541
7542         return TRUE;
7543 }
7544
7545 void
7546 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7547 {
7548         MMPLAYER_RETURN_IF_FAIL(player);
7549
7550         if (player->eos_timer) {
7551                 LOGD("cancel eos timer");
7552                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7553                 player->eos_timer = 0;
7554         }
7555
7556         return;
7557 }
7558
7559 static void
7560 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7561 {
7562         MMPLAYER_FENTER();
7563
7564         MMPLAYER_RETURN_IF_FAIL(player);
7565         MMPLAYER_RETURN_IF_FAIL(sink);
7566
7567         player->sink_elements = g_list_append(player->sink_elements, sink);
7568
7569         MMPLAYER_FLEAVE();
7570 }
7571
7572 static void
7573 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7574 {
7575         MMPLAYER_FENTER();
7576
7577         MMPLAYER_RETURN_IF_FAIL(player);
7578         MMPLAYER_RETURN_IF_FAIL(sink);
7579
7580         player->sink_elements = g_list_remove(player->sink_elements, sink);
7581
7582         MMPLAYER_FLEAVE();
7583 }
7584
7585 void
7586 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7587         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7588 {
7589         mmplayer_signal_item_t *item = NULL;
7590
7591         MMPLAYER_FENTER();
7592         MMPLAYER_RETURN_IF_FAIL(player);
7593
7594         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7595                 LOGE("invalid signal type [%d]", type);
7596                 return;
7597         }
7598
7599         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7600         if (!item) {
7601                 LOGE("cannot connect signal [%s]", signal);
7602                 return;
7603         }
7604
7605         item->obj = object;
7606         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7607         player->signals[type] = g_list_append(player->signals[type], item);
7608
7609         MMPLAYER_FLEAVE();
7610         return;
7611 }
7612
7613 /* NOTE : be careful with calling this api. please refer to below glib comment
7614  * glib comment : Note that there is a bug in GObject that makes this function much
7615  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7616  * will no longer be called, but, the signal handler is not currently disconnected.
7617  * If the instance is itself being freed at the same time than this doesn't matter,
7618  * since the signal will automatically be removed, but if instance persists,
7619  * then the signal handler will leak. You should not remove the signal yourself
7620  * because in a future versions of GObject, the handler will automatically be
7621  * disconnected.
7622  *
7623  * It's possible to work around this problem in a way that will continue to work
7624  * with future versions of GObject by checking that the signal handler is still
7625  * connected before disconnected it:
7626  *
7627  *  if (g_signal_handler_is_connected(instance, id))
7628  *    g_signal_handler_disconnect(instance, id);
7629  */
7630 static void
7631 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7632 {
7633         GList *sig_list = NULL;
7634         mmplayer_signal_item_t *item = NULL;
7635
7636         MMPLAYER_FENTER();
7637
7638         MMPLAYER_RETURN_IF_FAIL(player);
7639
7640         LOGD("release signals type : %d", type);
7641
7642         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7643                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7644                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7645                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7646                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7647                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7648                 return;
7649         }
7650
7651         sig_list = player->signals[type];
7652
7653         for (; sig_list; sig_list = sig_list->next) {
7654                 item = sig_list->data;
7655
7656                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7657                         if (g_signal_handler_is_connected(item->obj, item->sig))
7658                                 g_signal_handler_disconnect(item->obj, item->sig);
7659                 }
7660
7661                 MMPLAYER_FREEIF(item);
7662         }
7663
7664         g_list_free(player->signals[type]);
7665         player->signals[type] = NULL;
7666
7667         MMPLAYER_FLEAVE();
7668
7669         return;
7670 }
7671
7672 int
7673 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7674 {
7675         mmplayer_t *player = 0;
7676         int prev_display_surface_type = 0;
7677
7678         MMPLAYER_FENTER();
7679
7680         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7681
7682         player = MM_PLAYER_CAST(handle);
7683
7684         /* check video sinkbin is created */
7685         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7686                 LOGW("Videosink is already created");
7687                 return MM_ERROR_NONE;
7688         }
7689
7690         LOGD("videosink element is not yet ready");
7691
7692         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7693                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7694                 MMPLAYER_FLEAVE();
7695                 return MM_ERROR_INVALID_ARGUMENT;
7696         }
7697
7698         /* load previous attributes */
7699         if (player->attrs) {
7700                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7701                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7702                 if (prev_display_surface_type == surface_type) {
7703                         LOGD("incoming display surface type is same as previous one, do nothing..");
7704                         MMPLAYER_FLEAVE();
7705                         return MM_ERROR_NONE;
7706                 }
7707         } else {
7708                 LOGE("failed to load attributes");
7709                 MMPLAYER_FLEAVE();
7710                 return MM_ERROR_PLAYER_INTERNAL;
7711         }
7712
7713         /* videobin is not created yet, so we just set attributes related to display surface */
7714         LOGD("store display attribute for given surface type(%d)", surface_type);
7715         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7716                         "display_overlay", wl_surface_id, NULL);
7717
7718         MMPLAYER_FLEAVE();
7719         return MM_ERROR_NONE;
7720 }
7721
7722 /* Note : if silent is true, then subtitle would not be displayed. :*/
7723 int
7724 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7725 {
7726         mmplayer_t *player = (mmplayer_t *)hplayer;
7727
7728         MMPLAYER_FENTER();
7729
7730         /* check player handle */
7731         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7732
7733         player->set_mode.subtitle_off = silent;
7734
7735         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7736
7737         MMPLAYER_FLEAVE();
7738
7739         return MM_ERROR_NONE;
7740 }
7741
7742 int
7743 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7744 {
7745         mmplayer_gst_element_t *mainbin = NULL;
7746         mmplayer_gst_element_t *textbin = NULL;
7747         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7748         GstState current_state = GST_STATE_VOID_PENDING;
7749         GstState element_state = GST_STATE_VOID_PENDING;
7750         GstState element_pending_state = GST_STATE_VOID_PENDING;
7751         gint64 time = 0;
7752         GstEvent *event = NULL;
7753         int result = MM_ERROR_NONE;
7754
7755         GstClock *curr_clock = NULL;
7756         GstClockTime base_time, start_time, curr_time;
7757
7758
7759         MMPLAYER_FENTER();
7760
7761         /* check player handle */
7762         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7763                                                                 player->pipeline &&
7764                                                                 player->pipeline->mainbin &&
7765                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7766
7767         mainbin = player->pipeline->mainbin;
7768         textbin = player->pipeline->textbin;
7769
7770         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7771
7772         // sync clock with current pipeline
7773         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7774         curr_time = gst_clock_get_time(curr_clock);
7775
7776         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7777         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7778
7779         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7780                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7781
7782         if (current_state > GST_STATE_READY) {
7783                 // sync state with current pipeline
7784                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7785                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7786                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7787
7788                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7789                 if (GST_STATE_CHANGE_FAILURE == ret) {
7790                         LOGE("fail to state change.");
7791                         result = MM_ERROR_PLAYER_INTERNAL;
7792                         goto ERROR;
7793                 }
7794         }
7795         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7796         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7797
7798         if (curr_clock) {
7799                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7800                 gst_object_unref(curr_clock);
7801         }
7802
7803         // seek to current position
7804         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7805                 result = MM_ERROR_PLAYER_INVALID_STATE;
7806                 LOGE("gst_element_query_position failed, invalid state");
7807                 goto ERROR;
7808         }
7809
7810         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7811         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);
7812         if (event) {
7813                 _mmplayer_gst_send_event_to_sink(player, event);
7814         } else {
7815                 result = MM_ERROR_PLAYER_INTERNAL;
7816                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7817                 goto ERROR;
7818         }
7819
7820         /* sync state with current pipeline */
7821         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7822         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7823         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7824
7825         return MM_ERROR_NONE;
7826
7827 ERROR:
7828         /* release text pipeline resource */
7829         player->textsink_linked = 0;
7830
7831         /* release signal */
7832         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7833
7834         /* release textbin with it's childs */
7835         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7836         MMPLAYER_FREEIF(player->pipeline->textbin);
7837         player->pipeline->textbin = NULL;
7838
7839         /* release subtitle elem */
7840         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7841         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7842
7843         return result;
7844 }
7845
7846 static int
7847 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7848 {
7849         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7850         GstState current_state = GST_STATE_VOID_PENDING;
7851
7852         MMHandleType attrs = 0;
7853         mmplayer_gst_element_t *mainbin = NULL;
7854         mmplayer_gst_element_t *textbin = NULL;
7855
7856         gchar *subtitle_uri = NULL;
7857         int result = MM_ERROR_NONE;
7858         const gchar *charset = NULL;
7859
7860         MMPLAYER_FENTER();
7861
7862         /* check player handle */
7863         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7864                                                                 player->pipeline &&
7865                                                                 player->pipeline->mainbin &&
7866                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7867         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7868
7869         mainbin = player->pipeline->mainbin;
7870         textbin = player->pipeline->textbin;
7871
7872         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7873         if (current_state < GST_STATE_READY) {
7874                 result = MM_ERROR_PLAYER_INVALID_STATE;
7875                 LOGE("Pipeline is not in proper state");
7876                 goto EXIT;
7877         }
7878
7879         attrs = MMPLAYER_GET_ATTRS(player);
7880         if (!attrs) {
7881                 LOGE("cannot get content attribute");
7882                 result = MM_ERROR_PLAYER_INTERNAL;
7883                 goto EXIT;
7884         }
7885
7886         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7887         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7888                 LOGE("subtitle uri is not proper filepath");
7889                 result = MM_ERROR_PLAYER_INVALID_URI;
7890                 goto EXIT;
7891         }
7892
7893         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7894                 LOGE("failed to get storage info of subtitle path");
7895                 result = MM_ERROR_PLAYER_INVALID_URI;
7896                 goto EXIT;
7897         }
7898
7899         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7900         SECURE_LOGD("new subtitle file path is [%s]", filepath);
7901
7902         if (!strcmp(filepath, subtitle_uri)) {
7903                 LOGD("subtitle path is not changed");
7904                 goto EXIT;
7905         } else {
7906                 if (mm_player_set_attribute((MMHandleType)player, NULL,
7907                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7908                         LOGE("failed to set attribute");
7909                         goto EXIT;
7910                 }
7911         }
7912
7913         //gst_pad_set_blocked_async(src-srcpad, TRUE)
7914         MMPLAYER_SUBTITLE_INFO_LOCK(player);
7915         player->subtitle_language_list = NULL;
7916         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7917
7918         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7919         if (ret != GST_STATE_CHANGE_SUCCESS) {
7920                 LOGE("failed to change state of textbin to READY");
7921                 result = MM_ERROR_PLAYER_INTERNAL;
7922                 goto EXIT;
7923         }
7924
7925         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7926         if (ret != GST_STATE_CHANGE_SUCCESS) {
7927                 LOGE("failed to change state of subparse to READY");
7928                 result = MM_ERROR_PLAYER_INTERNAL;
7929                 goto EXIT;
7930         }
7931
7932         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7933         if (ret != GST_STATE_CHANGE_SUCCESS) {
7934                 LOGE("failed to change state of filesrc to READY");
7935                 result = MM_ERROR_PLAYER_INTERNAL;
7936                 goto EXIT;
7937         }
7938
7939         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7940
7941         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7942
7943         charset = _mmplayer_get_charset(filepath);
7944         if (charset) {
7945                 LOGD("detected charset is %s", charset);
7946                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7947         }
7948
7949         result = _mmplayer_sync_subtitle_pipeline(player);
7950
7951 EXIT:
7952         MMPLAYER_FLEAVE();
7953         return result;
7954 }
7955
7956 /* API to switch between external subtitles */
7957 int
7958 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7959 {
7960         int result = MM_ERROR_NONE;
7961         mmplayer_t *player = (mmplayer_t *)hplayer;
7962         char *path = NULL;
7963
7964         MMPLAYER_FENTER();
7965
7966         /* check player handle */
7967         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7968
7969         /* filepath can be null in idle state */
7970         if (filepath) {
7971                 /* check file path */
7972                 if ((path = strstr(filepath, "file://")))
7973                         result = _mmplayer_exist_file_path(path + 7);
7974                 else
7975                         result = _mmplayer_exist_file_path(filepath);
7976
7977                 if (result != MM_ERROR_NONE) {
7978                         LOGE("invalid subtitle path 0x%X", result);
7979                         return result; /* file not found or permission denied */
7980                 }
7981         }
7982
7983         if (!player->pipeline) {
7984                 /* IDLE state */
7985                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7986                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7987                         LOGE("failed to set attribute");
7988                         return MM_ERROR_PLAYER_INTERNAL;
7989                 }
7990         } else {
7991                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7992                 /* check filepath */
7993                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7994
7995                 if (!__mmplayer_check_subtitle(player)) {
7996                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
7997                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7998                                 LOGE("failed to set attribute");
7999                                 return MM_ERROR_PLAYER_INTERNAL;
8000                         }
8001
8002                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8003                                 LOGE("fail to create text pipeline");
8004                                 return MM_ERROR_PLAYER_INTERNAL;
8005                         }
8006
8007                         result = _mmplayer_sync_subtitle_pipeline(player);
8008                 } else {
8009                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8010                 }
8011
8012                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8013                 player->is_external_subtitle_added_now = TRUE;
8014
8015                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8016                 if (!player->subtitle_language_list) {
8017                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8018                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8019                                 LOGW("subtitle language list is not updated yet");
8020                 }
8021                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8022         }
8023
8024         MMPLAYER_FLEAVE();
8025         return result;
8026 }
8027
8028 static int
8029 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8030 {
8031         int result = MM_ERROR_NONE;
8032         gchar *change_pad_name = NULL;
8033         GstPad *sinkpad = NULL;
8034         mmplayer_gst_element_t *mainbin = NULL;
8035         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8036         GstCaps *caps = NULL;
8037         gint total_track_num = 0;
8038
8039         MMPLAYER_FENTER();
8040
8041         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8042                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8043
8044         LOGD("Change Track(%d) to %d", type, index);
8045
8046         mainbin = player->pipeline->mainbin;
8047
8048         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8049                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8050         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8051                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8052         } else {
8053                 /* Changing Video Track is not supported. */
8054                 LOGE("Track Type Error");
8055                 goto EXIT;
8056         }
8057
8058         if (mainbin[elem_idx].gst == NULL) {
8059                 result = MM_ERROR_PLAYER_NO_OP;
8060                 LOGD("Req track doesn't exist");
8061                 goto EXIT;
8062         }
8063
8064         total_track_num = player->selector[type].total_track_num;
8065         if (total_track_num <= 0) {
8066                 result = MM_ERROR_PLAYER_NO_OP;
8067                 LOGD("Language list is not available");
8068                 goto EXIT;
8069         }
8070
8071         if ((index < 0) || (index >= total_track_num)) {
8072                 result = MM_ERROR_INVALID_ARGUMENT;
8073                 LOGD("Not a proper index : %d", index);
8074                 goto EXIT;
8075         }
8076
8077         /*To get the new pad from the selector*/
8078         change_pad_name = g_strdup_printf("sink_%u", index);
8079         if (change_pad_name == NULL) {
8080                 result = MM_ERROR_PLAYER_INTERNAL;
8081                 LOGD("Pad does not exists");
8082                 goto EXIT;
8083         }
8084
8085         LOGD("new active pad name: %s", change_pad_name);
8086
8087         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8088         if (sinkpad == NULL) {
8089                 LOGD("sinkpad is NULL");
8090                 result = MM_ERROR_PLAYER_INTERNAL;
8091                 goto EXIT;
8092         }
8093
8094         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8095         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8096
8097         caps = gst_pad_get_current_caps(sinkpad);
8098         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8099
8100         if (sinkpad)
8101                 gst_object_unref(sinkpad);
8102
8103         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8104                 __mmplayer_set_audio_attrs(player, caps);
8105
8106 EXIT:
8107         MMPLAYER_FREEIF(change_pad_name);
8108         return result;
8109 }
8110
8111 int
8112 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8113 {
8114         int result = MM_ERROR_NONE;
8115         mmplayer_t *player = NULL;
8116         mmplayer_gst_element_t *mainbin = NULL;
8117
8118         gint current_active_index = 0;
8119
8120         GstState current_state = GST_STATE_VOID_PENDING;
8121         GstEvent *event = NULL;
8122         gint64 time = 0;
8123
8124         MMPLAYER_FENTER();
8125
8126         player = (mmplayer_t *)hplayer;
8127         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8128
8129         if (!player->pipeline) {
8130                 LOGE("Track %d pre setting -> %d", type, index);
8131
8132                 player->selector[type].active_pad_index = index;
8133                 goto EXIT;
8134         }
8135
8136         mainbin = player->pipeline->mainbin;
8137
8138         current_active_index = player->selector[type].active_pad_index;
8139
8140         /*If index is same as running index no need to change the pad*/
8141         if (current_active_index == index)
8142                 goto EXIT;
8143
8144         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8145                 result = MM_ERROR_PLAYER_INVALID_STATE;
8146                 goto EXIT;
8147         }
8148
8149         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8150         if (current_state < GST_STATE_PAUSED) {
8151                 result = MM_ERROR_PLAYER_INVALID_STATE;
8152                 LOGW("Pipeline not in porper state");
8153                 goto EXIT;
8154         }
8155
8156         result = __mmplayer_change_selector_pad(player, type, index);
8157         if (result != MM_ERROR_NONE) {
8158                 LOGE("change selector pad error");
8159                 goto EXIT;
8160         }
8161
8162         player->selector[type].active_pad_index = index;
8163
8164         if (current_state == GST_STATE_PLAYING) {
8165                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8166                         (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8167                         GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8168                 if (event) {
8169                         _mmplayer_gst_send_event_to_sink(player, event);
8170                 } else {
8171                         result = MM_ERROR_PLAYER_INTERNAL;
8172                         goto EXIT;
8173                 }
8174         }
8175
8176 EXIT:
8177         return result;
8178 }
8179
8180 int
8181 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8182 {
8183         mmplayer_t *player = (mmplayer_t *)hplayer;
8184
8185         MMPLAYER_FENTER();
8186
8187         /* check player handle */
8188         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8189
8190         *silent = player->set_mode.subtitle_off;
8191
8192         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8193
8194         MMPLAYER_FLEAVE();
8195
8196         return MM_ERROR_NONE;
8197 }
8198
8199 static gboolean
8200 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8201 {
8202         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8203         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8204
8205         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8206         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8207
8208         int idx = 0;
8209
8210         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8211                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8212                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8213                         mmplayer_dump_t *dump_s;
8214                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8215                         if (dump_s == NULL) {
8216                                 LOGE("malloc fail");
8217                                 return FALSE;
8218                         }
8219
8220                         dump_s->dump_element_file = NULL;
8221                         dump_s->dump_pad = NULL;
8222                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8223
8224                         if (dump_s->dump_pad) {
8225                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8226                                 snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN * 2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
8227                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8228                                 dump_s->probe_handle_id = gst_pad_add_probe(dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL);
8229                                 /* add list for removed buffer probe and close FILE */
8230                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8231                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8232                                 return TRUE;
8233                         } else {
8234                                 MMPLAYER_FREEIF(dump_s);
8235                                 LOGE("failed to get %s sink pad added", factory_name);
8236                         }
8237                 }
8238         }
8239         return FALSE;
8240 }
8241
8242 static GstPadProbeReturn
8243 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8244 {
8245         FILE *dump_data = (FILE *)u_data;
8246 //      int written = 0;
8247         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8248         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8249
8250         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8251
8252         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8253 #ifdef __DEBUG__
8254         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8255 #endif
8256         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8257
8258         gst_buffer_unmap(buffer, &probe_info);
8259
8260         return GST_PAD_PROBE_OK;
8261 }
8262
8263 static void
8264 __mmplayer_release_dump_list(GList *dump_list)
8265 {
8266         GList *d_list = dump_list;
8267
8268         if (!d_list)
8269                 return;
8270
8271         for (; d_list; d_list = g_list_next(d_list)) {
8272                 mmplayer_dump_t *dump_s = d_list->data;
8273                 if (dump_s->dump_pad) {
8274                         if (dump_s->probe_handle_id)
8275                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8276                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8277                 }
8278                 if (dump_s->dump_element_file) {
8279                         fclose(dump_s->dump_element_file);
8280                         dump_s->dump_element_file = NULL;
8281                 }
8282                 MMPLAYER_FREEIF(dump_s);
8283         }
8284         g_list_free(dump_list);
8285         dump_list = NULL;
8286 }
8287
8288 int
8289 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8290 {
8291         mmplayer_t *player = (mmplayer_t *)hplayer;
8292
8293         MMPLAYER_FENTER();
8294
8295         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8296         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8297
8298         *exist = (bool)player->has_closed_caption;
8299
8300         MMPLAYER_FLEAVE();
8301
8302         return MM_ERROR_NONE;
8303 }
8304
8305 void
8306 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8307 {
8308         MMPLAYER_FENTER();
8309         if (buffer) {
8310 #ifdef __DEBUG__
8311                 LOGD("unref internal gst buffer %p", buffer);
8312 #endif
8313                 gst_buffer_unref((GstBuffer *)buffer);
8314                 buffer = NULL;
8315         }
8316         MMPLAYER_FLEAVE();
8317 }
8318
8319 int
8320 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8321 {
8322         mmplayer_t *player = (mmplayer_t *)hplayer;
8323
8324         MMPLAYER_FENTER();
8325
8326         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8327         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8328
8329         if (MMPLAYER_IS_STREAMING(player))
8330                 *timeout = (int)player->ini.live_state_change_timeout;
8331         else
8332                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8333
8334         LOGD("timeout = %d", *timeout);
8335
8336         MMPLAYER_FLEAVE();
8337         return MM_ERROR_NONE;
8338 }
8339
8340 static void
8341 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8342 {
8343         int i = 0;
8344         MMPLAYER_FENTER();
8345         MMPLAYER_RETURN_IF_FAIL(player);
8346
8347         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8348
8349                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8350                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8351                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8352                         player->storage_info[i].id = -1;
8353                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8354
8355                         if (path_type != MMPLAYER_PATH_MAX)
8356                                 break;
8357                 }
8358         }
8359
8360         MMPLAYER_FLEAVE();
8361 }
8362
8363 int
8364 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8365 {
8366         int ret = MM_ERROR_NONE;
8367         mmplayer_t *player = (mmplayer_t *)hplayer;
8368         MMMessageParamType msg_param = {0, };
8369
8370         MMPLAYER_FENTER();
8371         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8372
8373         LOGW("state changed storage %d:%d", id, state);
8374
8375         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8376                 return MM_ERROR_NONE;
8377
8378         /* FIXME: text path should be handled seperately. */
8379         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8380                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8381                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8382                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8383                 LOGW("external storage is removed");
8384
8385                 if (player->msg_posted == FALSE) {
8386                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8387                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8388                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8389                         player->msg_posted = TRUE;
8390                 }
8391
8392                 /* unrealize the player */
8393                 ret = _mmplayer_unrealize(hplayer);
8394                 if (ret != MM_ERROR_NONE)
8395                         LOGE("failed to unrealize");
8396         }
8397
8398         MMPLAYER_FLEAVE();
8399         return ret;
8400 }
8401
8402 int
8403 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8404 {
8405         int ret = MM_ERROR_NONE;
8406         mmplayer_t *player = (mmplayer_t *)hplayer;
8407         int idx = 0, total = 0;
8408         gchar *result = NULL, *tmp = NULL;
8409
8410         MMPLAYER_FENTER();
8411         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8412         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8413
8414         total = *num = g_list_length(player->adaptive_info.var_list);
8415         if (total <= 0) {
8416                 LOGW("There is no stream variant info.");
8417                 return ret;
8418         }
8419
8420         result = g_strdup("");
8421         for (idx = 0 ; idx < total ; idx++) {
8422                 stream_variant_t *v_data = NULL;
8423                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8424
8425                 if (v_data) {
8426                         gchar data[64] = {0};
8427                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8428
8429                         tmp = g_strconcat(result, data, NULL);
8430                         g_free(result);
8431                         result = tmp;
8432                 } else {
8433                         LOGW("There is no variant data in %d", idx);
8434                         (*num)--;
8435                 }
8436         }
8437
8438         *var_info = (char *)result;
8439
8440         LOGD("variant info %d:%s", *num, *var_info);
8441         MMPLAYER_FLEAVE();
8442         return ret;
8443 }
8444
8445 int
8446 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8447 {
8448         int ret = MM_ERROR_NONE;
8449         mmplayer_t *player = (mmplayer_t *)hplayer;
8450
8451         MMPLAYER_FENTER();
8452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8453
8454         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8455
8456         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8457         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8458         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8459
8460         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8461                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8462                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8463                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8464
8465                 /* FIXME: seek to current position for applying new variant limitation */
8466         }
8467
8468         MMPLAYER_FLEAVE();
8469         return ret;
8470
8471 }
8472
8473 int
8474 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8475 {
8476         int ret = MM_ERROR_NONE;
8477         mmplayer_t *player = (mmplayer_t *)hplayer;
8478
8479         MMPLAYER_FENTER();
8480         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8481         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8482
8483         *bandwidth = player->adaptive_info.limit.bandwidth;
8484         *width = player->adaptive_info.limit.width;
8485         *height = player->adaptive_info.limit.height;
8486
8487         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8488
8489         MMPLAYER_FLEAVE();
8490         return ret;
8491 }
8492
8493 int
8494 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8495 {
8496         int ret = MM_ERROR_NONE;
8497         mmplayer_t *player = (mmplayer_t *)hplayer;
8498
8499         MMPLAYER_FENTER();
8500         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8501         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8502         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8503
8504         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8505
8506         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8507                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8508         else /* live case */
8509                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8510
8511         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8512
8513         MMPLAYER_FLEAVE();
8514         return ret;
8515 }
8516
8517 int
8518 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8519 {
8520 #define IDX_FIRST_SW_CODEC 0
8521         mmplayer_t *player = (mmplayer_t *)hplayer;
8522         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8523
8524         MMPLAYER_FENTER();
8525         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526
8527         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8528                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8529                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8530
8531         switch (stream_type) {
8532         case MM_PLAYER_STREAM_TYPE_AUDIO:
8533         /* to support audio codec selection, codec info have to be added in ini file as below.
8534            audio codec element hw = xxxx
8535            audio codec element sw = avdec */
8536                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8537                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8538                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8539                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8540                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8541                         return MM_ERROR_PLAYER_NO_OP;
8542                 }
8543         break;
8544         case MM_PLAYER_STREAM_TYPE_VIDEO:
8545         /* to support video codec selection, codec info have to be added in ini file as below.
8546            video codec element hw = omx
8547            video codec element sw = avdec */
8548                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8549                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8550                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8551                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8552                         LOGE("There is no video codec info for codec_type %d", codec_type);
8553                         return MM_ERROR_PLAYER_NO_OP;
8554                 }
8555         break;
8556         default:
8557                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8558                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8559         break;
8560         }
8561
8562         LOGD("update %s codec_type to %d", attr_name, codec_type);
8563         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8564
8565         MMPLAYER_FLEAVE();
8566         return MM_ERROR_NONE;
8567 }
8568
8569 int
8570 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8571 {
8572         mmplayer_t *player = (mmplayer_t *)hplayer;
8573         GstElement *rg_vol_element = NULL;
8574
8575         MMPLAYER_FENTER();
8576
8577         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8578
8579         player->sound.rg_enable = enabled;
8580
8581         /* just hold rgvolume enable value if pipeline is not ready */
8582         if (!player->pipeline || !player->pipeline->audiobin) {
8583                 LOGD("pipeline is not ready. holding rgvolume enable value");
8584                 return MM_ERROR_NONE;
8585         }
8586
8587         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8588
8589         if (!rg_vol_element) {
8590                 LOGD("rgvolume element is not created");
8591                 return MM_ERROR_PLAYER_INTERNAL;
8592         }
8593
8594         if (enabled)
8595                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8596         else
8597                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8598
8599         MMPLAYER_FLEAVE();
8600
8601         return MM_ERROR_NONE;
8602 }
8603
8604 int
8605 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8606 {
8607         mmplayer_t *player = (mmplayer_t *)hplayer;
8608         GstElement *rg_vol_element = NULL;
8609         gboolean enable = FALSE;
8610
8611         MMPLAYER_FENTER();
8612
8613         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8614         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8615
8616         /* just hold enable_rg value if pipeline is not ready */
8617         if (!player->pipeline || !player->pipeline->audiobin) {
8618                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8619                 *enabled = player->sound.rg_enable;
8620                 return MM_ERROR_NONE;
8621         }
8622
8623         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8624
8625         if (!rg_vol_element) {
8626                 LOGD("rgvolume element is not created");
8627                 return MM_ERROR_PLAYER_INTERNAL;
8628         }
8629
8630         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8631         *enabled = (bool)enable;
8632
8633         MMPLAYER_FLEAVE();
8634
8635         return MM_ERROR_NONE;
8636 }
8637
8638 int
8639 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8640 {
8641         mmplayer_t *player = (mmplayer_t *)hplayer;
8642         MMHandleType attrs = 0;
8643         int handle = 0;
8644         int ret = MM_ERROR_NONE;
8645
8646         MMPLAYER_FENTER();
8647
8648         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8649
8650         attrs = MMPLAYER_GET_ATTRS(player);
8651         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8652
8653         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8654         if (!handle) {
8655                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8656                 return MM_ERROR_PLAYER_INTERNAL;
8657         }
8658
8659         player->video_roi.scale_x = scale_x;
8660         player->video_roi.scale_y = scale_y;
8661         player->video_roi.scale_width = scale_width;
8662         player->video_roi.scale_height = scale_height;
8663
8664         /* check video sinkbin is created */
8665         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8666                 return MM_ERROR_NONE;
8667
8668         if (!gst_video_overlay_set_video_roi_area(
8669                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8670                 scale_x, scale_y, scale_width, scale_height))
8671                 ret = MM_ERROR_PLAYER_INTERNAL;
8672         else
8673                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8674                         scale_x, scale_y, scale_width, scale_height);
8675
8676         MMPLAYER_FLEAVE();
8677
8678         return ret;
8679 }
8680
8681 int
8682 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8683 {
8684         mmplayer_t *player = (mmplayer_t *)hplayer;
8685         int ret = MM_ERROR_NONE;
8686
8687         MMPLAYER_FENTER();
8688
8689         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8690         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8691
8692         *scale_x = player->video_roi.scale_x;
8693         *scale_y = player->video_roi.scale_y;
8694         *scale_width = player->video_roi.scale_width;
8695         *scale_height = player->video_roi.scale_height;
8696
8697         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8698                 *scale_x, *scale_y, *scale_width, *scale_height);
8699
8700         return ret;
8701 }
8702
8703 int
8704 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8705 {
8706         mmplayer_t* player = (mmplayer_t*)hplayer;
8707
8708         MMPLAYER_FENTER();
8709
8710         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8711
8712         player->client_pid = pid;
8713
8714         LOGD("client pid[%d] %p", pid, player);
8715
8716         MMPLAYER_FLEAVE();
8717
8718         return MM_ERROR_NONE;
8719 }
8720
8721 static gboolean
8722 __mmplayer_update_duration_value(mmplayer_t *player)
8723 {
8724         gboolean ret = FALSE;
8725         gint64 dur_nsec = 0;
8726         LOGD("try to update duration");
8727
8728         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8729                 player->duration = dur_nsec;
8730                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8731                 ret = TRUE;
8732         }
8733
8734         if (player->duration < 0) {
8735                 LOGW("duration is Non-Initialized !!!");
8736                 player->duration = 0;
8737         }
8738
8739         /* update streaming service type */
8740         player->streaming_type =  _mmplayer_get_stream_service_type(player);
8741
8742         /* check duration is OK */
8743         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8744                 /* FIXIT : find another way to get duration here. */
8745                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8746
8747         return ret;
8748 }
8749
8750 static gboolean
8751 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8752 {
8753         /* update audio params
8754         NOTE : We need original audio params and it can be only obtained from src pad of audio
8755         decoder. Below code only valid when we are not using 'resampler' just before
8756         'audioconverter'. */
8757         GstCaps *caps_a = NULL;
8758         GstPad *pad = NULL;
8759         gint samplerate = 0, channels = 0;
8760         GstStructure *p = NULL;
8761         GstElement *aconv = NULL;
8762
8763         LOGD("try to update audio attrs");
8764
8765         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8766
8767         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8768                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8769         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8770                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8771         } else {
8772                 LOGE("there is no audio converter");
8773                 return FALSE;
8774         }
8775
8776         pad = gst_element_get_static_pad(aconv, "sink");
8777
8778         if (!pad) {
8779                 LOGW("failed to get pad from audio converter");
8780                 return FALSE;
8781         }
8782
8783         caps_a = gst_pad_get_current_caps(pad);
8784         if (!caps_a) {
8785                 LOGW("not ready to get audio caps");
8786                 gst_object_unref(pad);
8787                 return FALSE;
8788         }
8789
8790         p = gst_caps_get_structure(caps_a, 0);
8791
8792         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8793
8794         gst_structure_get_int(p, "rate", &samplerate);
8795         gst_structure_get_int(p, "channels", &channels);
8796
8797         mm_player_set_attribute((MMHandleType)player, NULL,
8798                         "content_audio_samplerate", samplerate,
8799                         "content_audio_channels", channels, NULL);
8800
8801         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8802
8803         gst_caps_unref(caps_a);
8804         gst_object_unref(pad);
8805
8806         return TRUE;
8807 }
8808
8809 static gboolean
8810 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8811 {
8812         LOGD("try to update video attrs");
8813
8814         GstCaps *caps_v = NULL;
8815         GstPad *pad = NULL;
8816         gint tmpNu, tmpDe;
8817         gint width, height;
8818         GstStructure *p = NULL;
8819
8820         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8821         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8822
8823         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8824         if (!pad) {
8825                 LOGD("no videosink sink pad");
8826                 return FALSE;
8827         }
8828
8829         caps_v = gst_pad_get_current_caps(pad);
8830         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8831         if (!caps_v && player->v_stream_caps) {
8832                 caps_v = player->v_stream_caps;
8833                 gst_caps_ref(caps_v);
8834         }
8835
8836         if (!caps_v) {
8837                 LOGD("no negitiated caps from videosink");
8838                 gst_object_unref(pad);
8839                 return FALSE;
8840         }
8841
8842         p = gst_caps_get_structure(caps_v, 0);
8843         gst_structure_get_int(p, "width", &width);
8844         gst_structure_get_int(p, "height", &height);
8845
8846         mm_player_set_attribute((MMHandleType)player, NULL,
8847                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8848
8849         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8850
8851         SECURE_LOGD("width : %d     height : %d", width, height);
8852
8853         gst_caps_unref(caps_v);
8854         gst_object_unref(pad);
8855
8856         if (tmpDe > 0) {
8857                 mm_player_set_attribute((MMHandleType)player, NULL,
8858                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8859                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8860         }
8861
8862         return TRUE;
8863 }
8864
8865 static gboolean
8866 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8867 {
8868         gboolean ret = FALSE;
8869         guint64 data_size = 0;
8870         gchar *path = NULL;
8871         struct stat sb;
8872
8873         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8874         if (!player->duration)
8875                 return FALSE;
8876
8877         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8878                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8879                 if (stat(path, &sb) == 0)
8880                         data_size = (guint64)sb.st_size;
8881
8882         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8883                 data_size = player->http_content_size;
8884         }
8885
8886         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8887
8888         if (data_size) {
8889                 guint64 bitrate = 0;
8890                 guint64 msec_dur = 0;
8891
8892                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8893                 if (msec_dur > 0) {
8894                         bitrate = data_size * 8 * 1000 / msec_dur;
8895                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8896                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8897                         mm_player_set_attribute((MMHandleType)player, NULL,
8898                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8899                         ret = TRUE;
8900                 } else {
8901                         LOGD("player duration is less than 0");
8902                 }
8903         }
8904
8905         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8906                 if (player->total_bitrate) {
8907                         mm_player_set_attribute((MMHandleType)player, NULL,
8908                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8909                         ret = TRUE;
8910                 }
8911         }
8912
8913         return ret;
8914 }
8915
8916 static void
8917 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8918 {
8919         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8920         data->uri_type = uri_type;
8921 }
8922
8923 static int
8924 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8925 {
8926         int ret = MM_ERROR_PLAYER_INVALID_URI;
8927         int mem_size = 0;
8928         char *buffer = NULL;
8929         char *seperator = strchr(path, ',');
8930         char ext[100] = {0,}, size[100] = {0,};
8931
8932         if (seperator) {
8933                 if ((buffer = strstr(path, "ext="))) {
8934                         buffer += strlen("ext=");
8935
8936                         if (strlen(buffer)) {
8937                                 strncpy(ext, buffer, 99);
8938
8939                                 if ((seperator = strchr(ext, ','))
8940                                         || (seperator = strchr(ext, ' '))
8941                                         || (seperator = strchr(ext, '\0'))) {
8942                                         seperator[0] = '\0';
8943                                 }
8944                         }
8945                 }
8946
8947                 if ((buffer = strstr(path, "size="))) {
8948                         buffer += strlen("size=");
8949
8950                         if (strlen(buffer) > 0) {
8951                                 strncpy(size, buffer, 99);
8952
8953                                 if ((seperator = strchr(size, ','))
8954                                         || (seperator = strchr(size, ' '))
8955                                         || (seperator = strchr(size, '\0'))) {
8956                                         seperator[0] = '\0';
8957                                 }
8958
8959                                 mem_size = atoi(size);
8960                         }
8961                 }
8962         }
8963
8964         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8965
8966         if (mem_size && param) {
8967                 if (data->input_mem.buf)
8968                         free(data->input_mem.buf);
8969                 data->input_mem.buf = malloc(mem_size);
8970
8971                 if (data->input_mem.buf) {
8972                         memcpy(data->input_mem.buf, param, mem_size);
8973                         data->input_mem.len = mem_size;
8974                         ret = MM_ERROR_NONE;
8975                 } else {
8976                         LOGE("failed to alloc mem %d", mem_size);
8977                         ret = MM_ERROR_PLAYER_INTERNAL;
8978                 }
8979
8980                 data->input_mem.offset = 0;
8981                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8982         }
8983
8984         return ret;
8985 }
8986
8987 static int
8988 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8989 {
8990         gchar *location = NULL;
8991         GError *err = NULL;
8992         char *path = NULL;
8993         int ret = MM_ERROR_NONE;
8994
8995         if ((path = strstr(uri, "file://"))) {
8996                 location = g_filename_from_uri(uri, NULL, &err);
8997                 if (!location || (err != NULL)) {
8998                         LOGE("Invalid URI '%s' for filesrc: %s", path,
8999                                 (err != NULL) ? err->message : "unknown error");
9000                         if (err)
9001                                 g_error_free(err);
9002
9003                         MMPLAYER_FREEIF(location);
9004
9005                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9006                         return MM_ERROR_PLAYER_INVALID_URI;
9007                 }
9008                 LOGD("path from uri: %s", location);
9009         }
9010
9011         path = (location != NULL) ? (location) : ((char *)uri);
9012
9013
9014         ret = _mmplayer_exist_file_path(path);
9015
9016         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9017         if (ret == MM_ERROR_NONE) {
9018                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9019                 if (_mmplayer_is_sdp_file(path)) {
9020                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9021                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9022                 } else {
9023                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9024                 }
9025         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9026                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9027         } else {
9028                 LOGE("invalid uri, could not play..");
9029                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9030         }
9031
9032         MMPLAYER_FREEIF(location);
9033
9034         return ret;
9035 }
9036
9037 static mmplayer_video_decoded_data_info_t *
9038 __mmplayer_create_stream_from_pad(GstPad *pad)
9039 {
9040         GstCaps *caps = NULL;
9041         GstStructure *structure = NULL;
9042         unsigned int fourcc = 0;
9043         const gchar *string_format = NULL;
9044         mmplayer_video_decoded_data_info_t *stream = NULL;
9045         gint width, height;
9046         MMPixelFormatType format;
9047         GstVideoInfo info;
9048
9049         caps = gst_pad_get_current_caps(pad);
9050         if (!caps) {
9051                 LOGE("Caps is NULL.");
9052                 return NULL;
9053         }
9054
9055 #ifdef __DEBUG__
9056         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9057 #endif
9058         structure = gst_caps_get_structure(caps, 0);
9059         gst_structure_get_int(structure, "width", &width);
9060         gst_structure_get_int(structure, "height", &height);
9061         string_format = gst_structure_get_string(structure, "format");
9062
9063         if (string_format)
9064                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9065         format = _mmplayer_get_pixtype(fourcc);
9066         gst_video_info_from_caps(&info, caps);
9067         gst_caps_unref(caps);
9068
9069         /* moved here */
9070         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9071                 LOGE("Wrong condition!!");
9072                 return NULL;
9073         }
9074
9075         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9076         if (!stream) {
9077                 LOGE("failed to alloc mem for video data");
9078                 return NULL;
9079         }
9080
9081         stream->width = width;
9082         stream->height = height;
9083         stream->format = format;
9084         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9085
9086         return stream;
9087 }
9088
9089 static void
9090 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9091 {
9092         unsigned int pitch = 0;
9093         unsigned int size = 0;
9094         int index = 0;
9095         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9096         tbm_bo bo = NULL;
9097
9098         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9099                 bo = gst_tizen_memory_get_bos(mem, index);
9100                 if (bo)
9101                         stream->bo[index] = tbm_bo_ref(bo);
9102                 else
9103                         LOGE("failed to get bo for index %d", index);
9104         }
9105
9106         for (index = 0; index < stream->plane_num; index++) {
9107                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9108                 stream->stride[index] = pitch;
9109                 if (pitch)
9110                         stream->elevation[index] = size / pitch;
9111                 else
9112                         stream->elevation[index] = stream->height;
9113         }
9114 }
9115
9116 static gboolean
9117 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9118 {
9119         if (stream->format == MM_PIXEL_FORMAT_I420) {
9120                 int ret = TBM_SURFACE_ERROR_NONE;
9121                 tbm_surface_h surface;
9122                 tbm_surface_info_s info;
9123
9124                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9125
9126                 ret = tbm_surface_get_info(surface, &info);
9127                 if (ret != TBM_SURFACE_ERROR_NONE) {
9128                         tbm_surface_destroy(surface);
9129                         return FALSE;
9130                 }
9131
9132                 tbm_surface_destroy(surface);
9133                 stream->stride[0] = info.planes[0].stride;
9134                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9135                 stream->stride[1] = info.planes[1].stride;
9136                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9137                 stream->stride[2] = info.planes[2].stride;
9138                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9139                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9140         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9141                 stream->stride[0] = stream->width * 4;
9142                 stream->elevation[0] = stream->height;
9143                 stream->bo_size = stream->stride[0] * stream->height;
9144         } else {
9145                 LOGE("Not support format %d", stream->format);
9146                 return FALSE;
9147         }
9148
9149         return TRUE;
9150 }
9151
9152 static gboolean
9153 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9154 {
9155         tbm_bo_handle thandle;
9156         gboolean is_mapped;
9157         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9158         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9159         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9160         int i = 0;
9161         int j = 0;
9162         int k = 0;
9163         unsigned char *src = NULL;
9164         unsigned char *dest = NULL;
9165         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9166
9167         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9168         if (!is_mapped) {
9169                 LOGE("fail to gst_memory_map");
9170                 return FALSE;
9171         }
9172
9173         if (!mapinfo.data) {
9174                 LOGE("data pointer is wrong");
9175                 goto ERROR;
9176         }
9177
9178         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9179         if (!stream->bo[0]) {
9180                 LOGE("Fail to tbm_bo_alloc!!");
9181                 goto ERROR;
9182         }
9183
9184         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9185         if (!thandle.ptr) {
9186                 LOGE("thandle pointer is wrong");
9187                 goto ERROR;
9188         }
9189
9190         if (stream->format == MM_PIXEL_FORMAT_I420) {
9191                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9192                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9193                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9194                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9195
9196                 dest_offset[0] = 0;
9197                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9198                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9199
9200                 for (i = 0; i < 3; i++) {
9201                         src = mapinfo.data + src_offset[i];
9202                         dest = thandle.ptr + dest_offset[i];
9203
9204                         if (i > 0)
9205                                 k = 1;
9206
9207                         for (j = 0; j < stream->height >> k; j++) {
9208                                 memcpy(dest, src, stream->width>>k);
9209                                 src += src_stride[i];
9210                                 dest += stream->stride[i];
9211                         }
9212                 }
9213         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9214                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9215         } else {
9216                 LOGE("Not support format %d", stream->format);
9217                 goto ERROR;
9218         }
9219
9220         tbm_bo_unmap(stream->bo[0]);
9221         gst_memory_unmap(mem, &mapinfo);
9222
9223         return TRUE;
9224
9225 ERROR:
9226         if (stream->bo[0])
9227                 tbm_bo_unmap(stream->bo[0]);
9228
9229         if (is_mapped)
9230                 gst_memory_unmap(mem, &mapinfo);
9231
9232         return FALSE;
9233 }
9234
9235 static void
9236 __mmplayer_set_pause_state(mmplayer_t *player)
9237 {
9238         if (player->sent_bos)
9239                 return;
9240
9241         /* rtsp case, get content attrs by GstMessage */
9242         if (MMPLAYER_IS_RTSP_STREAMING(player))
9243                 return;
9244
9245         /* it's first time to update all content attrs. */
9246         _mmplayer_update_content_attrs(player, ATTR_ALL);
9247 }
9248
9249 static void
9250 __mmplayer_set_playing_state(mmplayer_t *player)
9251 {
9252         gchar *audio_codec = NULL;
9253
9254         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9255                 /* initialize because auto resume is done well. */
9256                 player->resumed_by_rewind = FALSE;
9257                 player->playback_rate = 1.0;
9258         }
9259
9260         if (player->sent_bos)
9261                 return;
9262
9263         /* try to get content metadata */
9264
9265         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9266          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9267          * legacy mmfw-player api
9268          */
9269         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9270
9271         if ((player->cmd == MMPLAYER_COMMAND_START)
9272                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9273                 __mmplayer_handle_missed_plugin(player);
9274         }
9275
9276         /* check audio codec field is set or not
9277          * we can get it from typefinder or codec's caps.
9278          */
9279         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9280
9281         /* The codec format can't be sent for audio only case like amr, mid etc.
9282          * Because, parser don't make related TAG.
9283          * So, if it's not set yet, fill it with found data.
9284          */
9285         if (!audio_codec) {
9286                 if (g_strrstr(player->type, "audio/midi"))
9287                         audio_codec = "MIDI";
9288                 else if (g_strrstr(player->type, "audio/x-amr"))
9289                         audio_codec = "AMR";
9290                 else if (g_strrstr(player->type, "audio/mpeg")
9291                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9292                         audio_codec = "AAC";
9293                 else
9294                         audio_codec = "unknown";
9295
9296                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9297                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9298                         LOGE("failed to set attribute");
9299
9300                 LOGD("set audio codec type with caps");
9301         }
9302
9303         return;
9304 }