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