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