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