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