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