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