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