7b555c138aeb9a88e5ec3bc68afd36d7e3b423fc
[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         MMPLAYER_FLEAVE();
5200         return ret;
5201 }
5202
5203 int
5204 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5205 {
5206         mmplayer_t *player = (mmplayer_t *)hplayer;
5207
5208         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209
5210         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5211 }
5212
5213 int
5214 _mmplayer_get_state(MMHandleType hplayer, int *state)
5215 {
5216         mmplayer_t *player = (mmplayer_t *)hplayer;
5217
5218         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5219
5220         *state = MMPLAYER_CURRENT_STATE(player);
5221
5222         return MM_ERROR_NONE;
5223 }
5224
5225 static int
5226 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5227 {
5228         GstElement *vol_element = NULL;
5229         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5230
5231         MMPLAYER_FENTER();
5232         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5233         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5234
5235         /* check pipeline handle */
5236         if (!player->pipeline || !player->pipeline->audiobin) {
5237                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5238
5239                 /* NOTE : stored value will be used in create_audiobin
5240                  * returning MM_ERROR_NONE here makes application to able to
5241                  * set audio volume or mute at anytime.
5242                  */
5243                 return MM_ERROR_NONE;
5244         }
5245
5246         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5247                 volume_elem_id = MMPLAYER_A_SINK;
5248
5249         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5250         if (!vol_element) {
5251                 LOGE("failed to get vol element %d", volume_elem_id);
5252                 return MM_ERROR_PLAYER_INTERNAL;
5253         }
5254
5255         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5256
5257         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5258                 LOGE("there is no '%s' property", prop_name);
5259                 return MM_ERROR_PLAYER_INTERNAL;
5260         }
5261
5262         if (!strcmp(prop_name, "volume")) {
5263                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5264         } else if (!strcmp(prop_name, "mute")) {
5265                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5266         } else {
5267                 LOGE("invalid property %s", prop_name);
5268                 return MM_ERROR_PLAYER_INTERNAL;
5269         }
5270
5271         return MM_ERROR_NONE;
5272 }
5273
5274 int
5275 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5276 {
5277         int ret = MM_ERROR_NONE;
5278         mmplayer_t *player = (mmplayer_t *)hplayer;
5279
5280         MMPLAYER_FENTER();
5281         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5282
5283         LOGD("volume = %f", volume);
5284
5285         /* invalid factor range or not */
5286         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5287                 LOGE("Invalid volume value");
5288                 return MM_ERROR_INVALID_ARGUMENT;
5289         }
5290
5291         player->sound.volume = volume;
5292
5293         ret = __mmplayer_gst_set_volume_property(player, "volume");
5294
5295         MMPLAYER_FLEAVE();
5296         return ret;
5297 }
5298
5299 int
5300 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5301 {
5302         mmplayer_t *player = (mmplayer_t *)hplayer;
5303
5304         MMPLAYER_FENTER();
5305
5306         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5307         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5308
5309         *volume = player->sound.volume;
5310
5311         LOGD("current vol = %f", *volume);
5312
5313         MMPLAYER_FLEAVE();
5314         return MM_ERROR_NONE;
5315 }
5316
5317 int
5318 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5319 {
5320         int ret = MM_ERROR_NONE;
5321         mmplayer_t *player = (mmplayer_t *)hplayer;
5322
5323         MMPLAYER_FENTER();
5324         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5325
5326         LOGD("mute = %d", mute);
5327
5328         player->sound.mute = mute;
5329
5330         ret = __mmplayer_gst_set_volume_property(player, "mute");
5331
5332         MMPLAYER_FLEAVE();
5333         return ret;
5334 }
5335
5336 int
5337 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5338 {
5339         mmplayer_t *player = (mmplayer_t *)hplayer;
5340
5341         MMPLAYER_FENTER();
5342
5343         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5344         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5345
5346         *mute = player->sound.mute;
5347
5348         LOGD("current mute = %d", *mute);
5349
5350         MMPLAYER_FLEAVE();
5351
5352         return MM_ERROR_NONE;
5353 }
5354
5355 int
5356 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5357 {
5358         mmplayer_t *player = (mmplayer_t *)hplayer;
5359
5360         MMPLAYER_FENTER();
5361
5362         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5363
5364         player->audio_stream_changed_cb = callback;
5365         player->audio_stream_changed_cb_user_param = user_param;
5366         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5367
5368         MMPLAYER_FLEAVE();
5369
5370         return MM_ERROR_NONE;
5371 }
5372
5373 int
5374 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5375 {
5376         mmplayer_t *player = (mmplayer_t *)hplayer;
5377
5378         MMPLAYER_FENTER();
5379
5380         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5381
5382         player->audio_decoded_cb = callback;
5383         player->audio_decoded_cb_user_param = user_param;
5384         player->audio_extract_opt = opt;
5385         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5386
5387         MMPLAYER_FLEAVE();
5388
5389         return MM_ERROR_NONE;
5390 }
5391
5392 int
5393 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5394 {
5395         mmplayer_t *player = (mmplayer_t *)hplayer;
5396
5397         MMPLAYER_FENTER();
5398
5399         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5400
5401         if (callback && !player->bufmgr)
5402                 player->bufmgr = tbm_bufmgr_init(-1);
5403
5404         player->set_mode.video_export = (callback) ? true : false;
5405         player->video_decoded_cb = callback;
5406         player->video_decoded_cb_user_param = user_param;
5407
5408         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5409
5410         MMPLAYER_FLEAVE();
5411
5412         return MM_ERROR_NONE;
5413 }
5414
5415 int
5416 _mmplayer_start(MMHandleType hplayer)
5417 {
5418         mmplayer_t *player = (mmplayer_t *)hplayer;
5419         gint ret = MM_ERROR_NONE;
5420
5421         MMPLAYER_FENTER();
5422
5423         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5424
5425         /* check current state */
5426         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5427
5428         /* start pipeline */
5429         ret = _mmplayer_gst_start(player);
5430         if (ret != MM_ERROR_NONE)
5431                 LOGE("failed to start player.");
5432
5433         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5434                 LOGD("force playing start even during buffering");
5435                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5436         }
5437
5438         MMPLAYER_FLEAVE();
5439
5440         return ret;
5441 }
5442
5443 /* NOTE: post "not supported codec message" to application
5444  * when one codec is not found during AUTOPLUGGING in MSL.
5445  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5446  * And, if any codec is not found, don't send message here.
5447  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5448  */
5449 int
5450 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5451 {
5452         MMMessageParamType msg_param;
5453         memset(&msg_param, 0, sizeof(MMMessageParamType));
5454         gboolean post_msg_direct = FALSE;
5455
5456         MMPLAYER_FENTER();
5457
5458         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5459
5460         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5461                         player->not_supported_codec, player->can_support_codec);
5462
5463         if (player->not_found_demuxer) {
5464                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5465                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5466
5467                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5468                 MMPLAYER_FREEIF(msg_param.data);
5469
5470                 return MM_ERROR_NONE;
5471         }
5472
5473         if (player->not_supported_codec) {
5474                 if (player->can_support_codec) {
5475                         // There is one codec to play
5476                         post_msg_direct = TRUE;
5477                 } else {
5478                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5479                                 post_msg_direct = TRUE;
5480                 }
5481
5482                 if (post_msg_direct) {
5483                         MMMessageParamType msg_param;
5484                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5485
5486                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5487                                 LOGW("not found AUDIO codec, posting error code to application.");
5488
5489                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5490                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5491                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5492                                 LOGW("not found VIDEO codec, posting error code to application.");
5493
5494                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5495                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5496                         }
5497
5498                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5499
5500                         MMPLAYER_FREEIF(msg_param.data);
5501
5502                         return MM_ERROR_NONE;
5503                 } else {
5504                         // no any supported codec case
5505                         LOGW("not found any codec, posting error code to application.");
5506
5507                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5508                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5509                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5510                         } else {
5511                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5512                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5513                         }
5514
5515                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5516
5517                         MMPLAYER_FREEIF(msg_param.data);
5518                 }
5519         }
5520
5521         MMPLAYER_FLEAVE();
5522
5523         return MM_ERROR_NONE;
5524 }
5525
5526 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5527 {
5528         GstState element_state = GST_STATE_VOID_PENDING;
5529         GstState element_pending_state = GST_STATE_VOID_PENDING;
5530         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5531         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5532
5533         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5534
5535         MMPLAYER_RECONFIGURE_LOCK(player);
5536         if (!player->gapless.reconfigure) {
5537                 MMPLAYER_RECONFIGURE_UNLOCK(player);
5538                 return;
5539         }
5540
5541         LOGI("reconfigure is under process");
5542         MMPLAYER_RECONFIGURE_WAIT(player);
5543         MMPLAYER_RECONFIGURE_UNLOCK(player);
5544         LOGI("reconfigure is completed.");
5545
5546         result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5547                                 &element_state, &element_pending_state, timeout * GST_SECOND);
5548         if (result == GST_STATE_CHANGE_FAILURE)
5549                 LOGW("failed to get pipeline state in %d sec", timeout);
5550
5551         return;
5552 }
5553
5554 /* NOTE : it should be able to call 'stop' anytime*/
5555 int
5556 _mmplayer_stop(MMHandleType hplayer)
5557 {
5558         mmplayer_t *player = (mmplayer_t *)hplayer;
5559         int ret = MM_ERROR_NONE;
5560
5561         MMPLAYER_FENTER();
5562
5563         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5564
5565         /* check current state */
5566         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5567
5568         /* need to wait till the rebuilding pipeline is completed */
5569         __mmplayer_check_pipeline_reconfigure_state(player);
5570         MMPLAYER_RECONFIGURE_LOCK(player);
5571         __mmplayer_reset_gapless_state(player);
5572         MMPLAYER_RECONFIGURE_UNLOCK(player);
5573
5574         /* NOTE : application should not wait for EOS after calling STOP */
5575         _mmplayer_cancel_eos_timer(player);
5576
5577         /* reset */
5578         player->seek_state = MMPLAYER_SEEK_NONE;
5579
5580         /* stop pipeline */
5581         ret = _mmplayer_gst_stop(player);
5582
5583         if (ret != MM_ERROR_NONE)
5584                 LOGE("failed to stop player.");
5585
5586         MMPLAYER_FLEAVE();
5587
5588         return ret;
5589 }
5590
5591 int
5592 _mmplayer_pause(MMHandleType hplayer)
5593 {
5594         mmplayer_t *player = (mmplayer_t *)hplayer;
5595         gint64 pos_nsec = 0;
5596         gboolean async = FALSE;
5597         gint ret = MM_ERROR_NONE;
5598
5599         MMPLAYER_FENTER();
5600
5601         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5602
5603         /* check current state */
5604         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5605
5606         /* check pipline reconfigure state */
5607         __mmplayer_check_pipeline_reconfigure_state(player);
5608
5609         switch (MMPLAYER_CURRENT_STATE(player)) {
5610         case MM_PLAYER_STATE_READY:
5611                 {
5612                         /* check prepare async or not.
5613                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5614                          */
5615                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5616                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5617
5618                         /* Changing back sync of rtspsrc to async */
5619                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5620                                 LOGD("async prepare working mode for rtsp");
5621                                 async = TRUE;
5622                         }
5623                 }
5624                 break;
5625
5626         case MM_PLAYER_STATE_PLAYING:
5627                 {
5628                         /* NOTE : store current point to overcome some bad operation
5629                         *(returning zero when getting current position in paused state) of some
5630                         * elements
5631                         */
5632                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5633                                 LOGW("getting current position failed in paused");
5634
5635                         player->last_position = pos_nsec;
5636
5637                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5638                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5639                            This causes problem is position calculation during normal pause resume scenarios also.
5640                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5641                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5642                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5643                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5644                         }
5645                 }
5646                 break;
5647         }
5648
5649         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5650                 LOGD("doing async pause in case of ms buff src");
5651                 async = TRUE;
5652         }
5653
5654         /* pause pipeline */
5655         ret = _mmplayer_gst_pause(player, async);
5656         if (ret != MM_ERROR_NONE) {
5657                 LOGE("failed to pause player. ret : 0x%x", ret);
5658                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5659                 return ret;
5660         }
5661
5662         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5663                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5664                         LOGE("failed to update display_rotation");
5665         }
5666
5667         MMPLAYER_FLEAVE();
5668         return MM_ERROR_NONE;
5669 }
5670
5671 /* in case of streaming, pause could take long time.*/
5672 int
5673 _mmplayer_abort_pause(MMHandleType hplayer)
5674 {
5675         mmplayer_t *player = (mmplayer_t *)hplayer;
5676         int ret = MM_ERROR_NONE;
5677
5678         MMPLAYER_FENTER();
5679
5680         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5681                                                 player->pipeline &&
5682                                                 player->pipeline->mainbin,
5683                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5684
5685         LOGD("set the pipeline state to READY");
5686
5687         /* set state to READY */
5688         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5689                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5690         if (ret != MM_ERROR_NONE) {
5691                 LOGE("fail to change state to READY");
5692                 return MM_ERROR_PLAYER_INTERNAL;
5693         }
5694
5695         LOGD("succeeded in changing state to READY");
5696         return ret;
5697 }
5698
5699 int
5700 _mmplayer_resume(MMHandleType hplayer)
5701 {
5702         mmplayer_t *player = (mmplayer_t *)hplayer;
5703         int ret = MM_ERROR_NONE;
5704         gboolean async = FALSE;
5705
5706         MMPLAYER_FENTER();
5707
5708         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5709
5710         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5711                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5712                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5713                         return ret;
5714                 }
5715
5716                 /* Changing back sync mode rtspsrc to async */
5717                 LOGD("async resume for rtsp case");
5718                 async = TRUE;
5719         }
5720
5721         /* check current state */
5722         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5723
5724         ret = _mmplayer_gst_resume(player, async);
5725         if (ret != MM_ERROR_NONE)
5726                 LOGE("failed to resume player.");
5727
5728         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5729                 LOGD("force resume even during buffering");
5730                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5731         }
5732
5733         MMPLAYER_FLEAVE();
5734
5735         return ret;
5736 }
5737
5738 int
5739 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5740 {
5741         mmplayer_t *player = (mmplayer_t *)hplayer;
5742         gint64 pos_nsec = 0;
5743         int ret = MM_ERROR_NONE;
5744         bool mute = false;
5745         signed long long start = 0, stop = 0;
5746         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5747         MMPLAYER_FENTER();
5748
5749         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5750         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5751
5752         /* The sound of video is not supported under 0.0 and over 2.0. */
5753         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5754                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5755                         mute = true;
5756         }
5757         _mmplayer_set_mute(hplayer, mute);
5758
5759         if (player->playback_rate == rate)
5760                 return MM_ERROR_NONE;
5761
5762         /* If the position is reached at start potion during fast backward, EOS is posted.
5763          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5764          */
5765         player->playback_rate = rate;
5766
5767         current_state = MMPLAYER_CURRENT_STATE(player);
5768
5769         if (current_state != MM_PLAYER_STATE_PAUSED)
5770                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5771
5772         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5773
5774         if ((current_state == MM_PLAYER_STATE_PAUSED)
5775                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5776                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5777                 pos_nsec = player->last_position;
5778         }
5779
5780         if (rate >= 0) {
5781                 start = pos_nsec;
5782                 stop = GST_CLOCK_TIME_NONE;
5783         } else {
5784                 start = GST_CLOCK_TIME_NONE;
5785                 stop = pos_nsec;
5786         }
5787
5788         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5789                                 player->playback_rate,
5790                                 GST_FORMAT_TIME,
5791                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5792                                 GST_SEEK_TYPE_SET, start,
5793                                 GST_SEEK_TYPE_SET, stop)) {
5794                 LOGE("failed to set speed playback");
5795                 return MM_ERROR_PLAYER_SEEK;
5796         }
5797
5798         LOGD("succeeded to set speed playback as %0.1f", rate);
5799
5800         MMPLAYER_FLEAVE();
5801
5802         return MM_ERROR_NONE;;
5803 }
5804
5805 int
5806 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5807 {
5808         mmplayer_t *player = (mmplayer_t *)hplayer;
5809         int ret = MM_ERROR_NONE;
5810
5811         MMPLAYER_FENTER();
5812
5813         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5814
5815         /* check pipline reconfigure state */
5816         __mmplayer_check_pipeline_reconfigure_state(player);
5817
5818         ret = _mmplayer_gst_set_position(player, position, FALSE);
5819
5820         MMPLAYER_FLEAVE();
5821
5822         return ret;
5823 }
5824
5825 int
5826 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5827 {
5828         mmplayer_t *player = (mmplayer_t *)hplayer;
5829         int ret = MM_ERROR_NONE;
5830
5831         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5832         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5833
5834         if (g_strrstr(player->type, "video/mpegts"))
5835                 __mmplayer_update_duration_value(player);
5836
5837         *duration = player->duration;
5838         return ret;
5839 }
5840
5841 int
5842 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5843 {
5844         mmplayer_t *player = (mmplayer_t *)hplayer;
5845         int ret = MM_ERROR_NONE;
5846
5847         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5848
5849         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5850
5851         return ret;
5852 }
5853
5854 int
5855 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5856 {
5857         mmplayer_t *player = (mmplayer_t *)hplayer;
5858         int ret = MM_ERROR_NONE;
5859
5860         MMPLAYER_FENTER();
5861
5862         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5863
5864         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5865
5866         MMPLAYER_FLEAVE();
5867
5868         return ret;
5869 }
5870
5871 static gboolean
5872 __mmplayer_is_midi_type(gchar *str_caps)
5873 {
5874         if ((g_strrstr(str_caps, "audio/midi")) ||
5875                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5876                 (g_strrstr(str_caps, "application/x-smaf")) ||
5877                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5878                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5879                 (g_strrstr(str_caps, "audio/xmf")) ||
5880                 (g_strrstr(str_caps, "audio/mxmf"))) {
5881                 LOGD("midi");
5882                 return TRUE;
5883         }
5884
5885         return FALSE;
5886 }
5887
5888 static gboolean
5889 __mmplayer_is_only_mp3_type(gchar *str_caps)
5890 {
5891         if (g_strrstr(str_caps, "application/x-id3") ||
5892                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5893                 return TRUE;
5894         return FALSE;
5895 }
5896
5897 void
5898 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5899 {
5900         GstStructure *caps_structure = NULL;
5901         gint samplerate = 0;
5902         gint channels = 0;
5903
5904         MMPLAYER_FENTER();
5905         MMPLAYER_RETURN_IF_FAIL(player && caps);
5906
5907         caps_structure = gst_caps_get_structure(caps, 0);
5908
5909         /* set stream information */
5910         gst_structure_get_int(caps_structure, "rate", &samplerate);
5911         gst_structure_get_int(caps_structure, "channels", &channels);
5912
5913         mm_player_set_attribute((MMHandleType)player, NULL,
5914                         "content_audio_samplerate", samplerate,
5915                         "content_audio_channels", channels, NULL);
5916
5917         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5918 }
5919
5920 static void
5921 __mmplayer_update_content_type_info(mmplayer_t *player)
5922 {
5923         MMPLAYER_FENTER();
5924         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5925
5926         if (__mmplayer_is_midi_type(player->type)) {
5927                 player->bypass_audio_effect = TRUE;
5928                 return;
5929         }
5930
5931         if (!player->streamer) {
5932                 LOGD("no need to check streaming type");
5933                 return;
5934         }
5935
5936         if (g_strrstr(player->type, "application/x-hls")) {
5937                 /* If it can't know exact type when it parses uri because of redirection case,
5938                  * it will be fixed by typefinder or when doing autoplugging.
5939                  */
5940                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5941                 player->streamer->is_adaptive_streaming = TRUE;
5942         } else if (g_strrstr(player->type, "application/dash+xml")) {
5943                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5944                 player->streamer->is_adaptive_streaming = TRUE;
5945         }
5946
5947         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5948         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5949                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5950
5951                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5952                         if (player->streamer->is_adaptive_streaming)
5953                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5954                         else
5955                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5956                 }
5957         }
5958
5959         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5960         MMPLAYER_FLEAVE();
5961 }
5962
5963 void
5964 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5965         GstCaps *caps, gpointer data)
5966 {
5967         mmplayer_t *player = (mmplayer_t *)data;
5968
5969         MMPLAYER_FENTER();
5970
5971         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5972
5973         /* store type string */
5974         if (player->type_caps) {
5975                 gst_caps_unref(player->type_caps);
5976                 player->type_caps = NULL;
5977         }
5978
5979         player->type_caps = gst_caps_copy(caps);
5980         MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5981
5982         MMPLAYER_FREEIF(player->type);
5983         player->type = gst_caps_to_string(caps);
5984         if (player->type)
5985                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5986                                 player, player->type, probability, gst_caps_get_size(caps));
5987
5988         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5989                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5990                 LOGE("not support media format");
5991
5992                 if (player->msg_posted == FALSE) {
5993                         MMMessageParamType msg_param;
5994                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5995
5996                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5997                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5998
5999                         /* don't post more if one was sent already */
6000                         player->msg_posted = TRUE;
6001                 }
6002                 return;
6003         }
6004
6005         __mmplayer_update_content_type_info(player);
6006
6007         if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6008                 GstPad *pad = NULL;
6009
6010                 pad = gst_element_get_static_pad(tf, "src");
6011                 if (!pad) {
6012                         LOGE("fail to get typefind src pad.");
6013                         return;
6014                 }
6015
6016                 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6017                         gboolean async = FALSE;
6018                         LOGE("failed to autoplug %s", player->type);
6019
6020                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6021
6022                         if (async && player->msg_posted == FALSE)
6023                                 __mmplayer_handle_missed_plugin(player);
6024                 }
6025                 gst_object_unref(GST_OBJECT(pad));
6026         }
6027         MMPLAYER_FLEAVE();
6028         return;
6029 }
6030
6031 GstElement *
6032 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6033 {
6034         GstElement *decodebin = NULL;
6035
6036         MMPLAYER_FENTER();
6037
6038         /* create decodebin */
6039         decodebin = gst_element_factory_make("decodebin", NULL);
6040
6041         if (!decodebin) {
6042                 LOGE("fail to create decodebin");
6043                 goto ERROR;
6044         }
6045
6046         /* raw pad handling signal */
6047         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6048                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6049
6050         /* no-more-pad pad handling signal */
6051         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6052                                                 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6053
6054         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6055                                                 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6056
6057         /* This signal is emitted when a pad for which there is no further possible
6058            decoding is added to the decodebin.*/
6059         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6060                                                 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6061
6062         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6063            before looking for any elements that can handle that stream.*/
6064         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6065                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6066
6067         if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6068                 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6069                                                         G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6070
6071         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6072            before looking for any elements that can handle that stream.*/
6073         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6074                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6075
6076         /* This signal is emitted once decodebin has finished decoding all the data.*/
6077         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6078                                                 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6079
6080         /* This signal is emitted when a element is added to the bin.*/
6081         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6082                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6083
6084 ERROR:
6085         return decodebin;
6086 }
6087
6088 static GstElement *
6089 __mmplayer_gst_make_queue2(mmplayer_t *player)
6090 {
6091         GstElement *queue2 = NULL;
6092         gint64 dur_bytes = 0L;
6093         mmplayer_gst_element_t *mainbin = NULL;
6094         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6095
6096         MMPLAYER_FENTER();
6097         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6098
6099         mainbin = player->pipeline->mainbin;
6100
6101         queue2 = gst_element_factory_make("queue2", "queue2");
6102         if (!queue2) {
6103                 LOGE("failed to create buffering queue element");
6104                 return NULL;
6105         }
6106
6107         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6108                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6109
6110         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6111
6112         /* NOTE : in case of ts streaming, player could not get the correct duration info *
6113          *                skip the pull mode(file or ring buffering) setting. */
6114         if (dur_bytes > 0) {
6115                 if (!g_strrstr(player->type, "video/mpegts")) {
6116                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6117                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6118                 }
6119         } else {
6120                 dur_bytes = 0;
6121         }
6122
6123         _mm_player_streaming_set_queue2(player->streamer,
6124                                                                         queue2,
6125                                                                         FALSE,
6126                                                                         type,
6127                                                                         (guint64)dur_bytes); /* no meaning at the moment */
6128
6129         return queue2;
6130 }
6131
6132 gboolean
6133 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6134 {
6135         mmplayer_gst_element_t *mainbin = NULL;
6136         GstElement *decodebin = NULL;
6137         GstElement *queue2 = NULL;
6138         GstPad *sinkpad = NULL;
6139         GstPad *qsrcpad = NULL;
6140
6141         MMPLAYER_FENTER();
6142         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6143
6144         mainbin = player->pipeline->mainbin;
6145
6146         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6147
6148                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6149                         LOGW("need to check: muxed buffer is not null");
6150                 }
6151
6152                 queue2 = __mmplayer_gst_make_queue2(player);
6153                 if (!queue2) {
6154                         LOGE("failed to make queue2");
6155                         goto ERROR;
6156                 }
6157
6158                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6159                         LOGE("failed to add buffering queue");
6160                         goto ERROR;
6161                 }
6162
6163                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6164                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6165
6166                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6167                         LOGE("failed to link [%s:%s]-[%s:%s]",
6168                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6169                         goto ERROR;
6170                 }
6171
6172                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6173                         LOGE("failed to sync queue2 state with parent");
6174                         goto ERROR;
6175                 }
6176
6177                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6178                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6179
6180                 srcpad = qsrcpad;
6181
6182                 gst_object_unref(GST_OBJECT(sinkpad));
6183                 sinkpad = NULL;
6184         }
6185
6186         /* create decodebin */
6187         decodebin = _mmplayer_gst_make_decodebin(player);
6188         if (!decodebin) {
6189                 LOGE("failed to make decodebin");
6190                 goto ERROR;
6191         }
6192
6193         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6194                 LOGE("failed to add decodebin");
6195                 goto ERROR;
6196         }
6197
6198         /* to force caps on the decodebin element and avoid reparsing stuff by
6199         * typefind. It also avoids a deadlock in the way typefind activates pads in
6200         * the state change */
6201         g_object_set(decodebin, "sink-caps", caps, NULL);
6202
6203         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6204
6205         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6206                 LOGE("failed to link [%s:%s]-[%s:%s]",
6207                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6208                 goto ERROR;
6209         }
6210
6211         gst_object_unref(GST_OBJECT(sinkpad));
6212         sinkpad = NULL;
6213         gst_object_unref(GST_OBJECT(qsrcpad));
6214         qsrcpad = NULL;
6215
6216         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6217         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6218
6219         /* set decodebin property about buffer in streaming playback. *
6220          * in case of HLS/DASH, it does not need to have big buffer   *
6221          * because it is kind of adaptive streaming.                  */
6222         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6223                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6224                 gint high_percent = 0;
6225
6226                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6227                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6228
6229                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6230
6231                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6232
6233                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6234                                                                                         "high-percent", high_percent,
6235                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6236                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6237                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6238         }
6239
6240         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6241                 LOGE("failed to sync decodebin state with parent");
6242                 goto ERROR;
6243         }
6244
6245         MMPLAYER_FLEAVE();
6246
6247         return TRUE;
6248
6249 ERROR:
6250
6251         if (sinkpad)
6252                 gst_object_unref(GST_OBJECT(sinkpad));
6253
6254         if (qsrcpad)
6255                 gst_object_unref(GST_OBJECT(qsrcpad));
6256
6257         if (queue2) {
6258                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6259                  * You need to explicitly set elements to the NULL state before
6260                  * dropping the final reference, to allow them to clean up.
6261                  */
6262                 gst_element_set_state(queue2, GST_STATE_NULL);
6263
6264                 /* And, it still has a parent "player".
6265                  * You need to let the parent manage the object instead of unreffing the object directly.
6266                  */
6267                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6268                 gst_object_unref(queue2);
6269                 queue2 = NULL;
6270         }
6271
6272         if (decodebin) {
6273                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6274                  * You need to explicitly set elements to the NULL state before
6275                  * dropping the final reference, to allow them to clean up.
6276                  */
6277                 gst_element_set_state(decodebin, GST_STATE_NULL);
6278
6279                 /* And, it still has a parent "player".
6280                  * You need to let the parent manage the object instead of unreffing the object directly.
6281                  */
6282
6283                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6284                 gst_object_unref(decodebin);
6285                 decodebin = NULL;
6286         }
6287
6288         return FALSE;
6289 }
6290
6291 static int
6292 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6293 {
6294         MMPLAYER_FENTER();
6295
6296         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6297         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6298
6299         LOGD("class : %s, mime : %s", factory_class, mime);
6300
6301         /* add missing plugin */
6302         /* NOTE : msl should check missing plugin for image mime type.
6303          * Some motion jpeg clips can have playable audio track.
6304          * So, msl have to play audio after displaying popup written video format not supported.
6305          */
6306         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6307                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6308                         LOGD("not found demuxer");
6309                         player->not_found_demuxer = TRUE;
6310                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6311
6312                         goto DONE;
6313                 }
6314         }
6315
6316         if (!g_strrstr(factory_class, "Demuxer")) {
6317                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6318                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6319                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6320
6321                         /* check that clip have multi tracks or not */
6322                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6323                                 LOGD("video plugin is already linked");
6324                         } else {
6325                                 LOGW("add VIDEO to missing plugin");
6326                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6327                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6328                         }
6329                 } else if (g_str_has_prefix(mime, "audio")) {
6330                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6331                                 LOGD("audio plugin is already linked");
6332                         } else {
6333                                 LOGW("add AUDIO to missing plugin");
6334                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6335                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6336                         }
6337                 }
6338         }
6339
6340 DONE:
6341         MMPLAYER_FLEAVE();
6342
6343         return MM_ERROR_NONE;
6344 }
6345
6346 void
6347 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6348 {
6349         mmplayer_t *player = (mmplayer_t *)data;
6350
6351         MMPLAYER_FENTER();
6352
6353         MMPLAYER_RETURN_IF_FAIL(player);
6354
6355         /* remove fakesink. */
6356         if (!_mmplayer_gst_remove_fakesink(player,
6357                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6358                 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6359                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6360                  * source element are not same. To overcome this situation, this function will called
6361                  * several places and several times. Therefore, this is not an error case.
6362                  */
6363                 return;
6364         }
6365
6366         LOGD("[handle: %p] pipeline has completely constructed", player);
6367
6368         if ((player->msg_posted == FALSE) &&
6369                 (player->cmd >= MMPLAYER_COMMAND_START))
6370                 __mmplayer_handle_missed_plugin(player);
6371
6372         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6373 }
6374
6375 static int
6376 __mmplayer_check_profile(void)
6377 {
6378         char *profileName;
6379         static int profile_tv = -1;
6380
6381         if (__builtin_expect(profile_tv != -1, 1))
6382                 return profile_tv;
6383
6384         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6385         switch (*profileName) {
6386         case 't':
6387         case 'T':
6388                 profile_tv = 1;
6389                 break;
6390         default:
6391                 profile_tv = 0;
6392                 break;
6393         }
6394         free(profileName);
6395
6396         return profile_tv;
6397 }
6398
6399 static gboolean
6400 __mmplayer_get_next_uri(mmplayer_t *player)
6401 {
6402         mmplayer_parse_profile_t profile;
6403         gint uri_idx = 0;
6404         guint num_of_list = 0;
6405         char *uri = NULL;
6406
6407         num_of_list = g_list_length(player->uri_info.uri_list);
6408         uri_idx = player->uri_info.uri_idx;
6409
6410         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6411         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6412                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6413                 if (!uri) {
6414                         LOGW("next uri does not exist");
6415                         continue;
6416                 }
6417
6418                 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6419                         LOGE("failed to parse profile");
6420                         continue;
6421                 }
6422
6423                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6424                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6425                         LOGW("uri type is not supported(%d)", profile.uri_type);
6426                         continue;
6427                 }
6428
6429                 LOGD("success to find next uri %d", uri_idx);
6430                 break;
6431         }
6432
6433         if (!uri || uri_idx == num_of_list) {
6434                 LOGE("failed to find next uri");
6435                 return FALSE;
6436         }
6437
6438         player->uri_info.uri_idx = uri_idx;
6439         if (mm_player_set_attribute((MMHandleType)player, NULL,
6440                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6441                 LOGE("failed to set attribute");
6442                 return FALSE;
6443         }
6444
6445         SECURE_LOGD("next playback uri: %s", uri);
6446         return TRUE;
6447 }
6448
6449 static gboolean
6450 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6451 {
6452 #define REPEAT_COUNT_INFINITE -1
6453 #define REPEAT_COUNT_MIN 2
6454 #define ORIGINAL_URI_ONLY 1
6455
6456         MMHandleType attrs = 0;
6457         gint video = 0;
6458         gint count = 0;
6459         gint gapless = 0;
6460         guint num_of_uri = 0;
6461         int profile_tv = -1;
6462
6463         MMPLAYER_FENTER();
6464
6465         LOGD("checking for gapless play option");
6466
6467         if (player->build_audio_offload) {
6468                 LOGE("offload path is not supportable.");
6469                 goto ERROR;
6470         }
6471
6472         if (player->pipeline->textbin) {
6473                 LOGE("subtitle path is enabled. gapless play is not supported.");
6474                 goto ERROR;
6475         }
6476
6477         attrs = MMPLAYER_GET_ATTRS(player);
6478         if (!attrs) {
6479                 LOGE("fail to get attributes.");
6480                 goto ERROR;
6481         }
6482
6483         mm_attrs_multiple_get(player->attrs, NULL,
6484                         "content_video_found", &video,
6485                         "profile_play_count", &count,
6486                         MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6487
6488         /* gapless playback is not supported in case of video at TV profile. */
6489         profile_tv = __mmplayer_check_profile();
6490         if (profile_tv && video) {
6491                 LOGW("not support video gapless playback");
6492                 goto ERROR;
6493         }
6494
6495         /* check repeat count in case of audio */
6496         if (!gapless &&
6497                 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6498                 LOGW("gapless is disabled");
6499                 goto ERROR;
6500         }
6501
6502         num_of_uri = g_list_length(player->uri_info.uri_list);
6503
6504         LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6505
6506         if (num_of_uri == ORIGINAL_URI_ONLY) {
6507                 /* audio looping path */
6508                 if (count >= REPEAT_COUNT_MIN) {
6509                         /* decrease play count */
6510                         /* we succeeded to rewind. update play count and then wait for next EOS */
6511                         count--;
6512                         mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6513                 } else if (count != REPEAT_COUNT_INFINITE) {
6514                         LOGD("there is no next uri and no repeat");
6515                         goto ERROR;
6516                 }
6517                 LOGD("looping cnt %d", count);
6518         } else {
6519                 /* gapless playback path */
6520                 if (!__mmplayer_get_next_uri(player)) {
6521                         LOGE("failed to get next uri");
6522                         goto ERROR;
6523                 }
6524         }
6525         return TRUE;
6526
6527 ERROR:
6528         LOGE("unable to play gapless path. EOS will be posted soon");
6529         return FALSE;
6530 }
6531
6532 static void
6533 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6534 {
6535         GstPad *sinkpad = g_value_get_object (item);
6536         GstElement *element = GST_ELEMENT(user_data);
6537         LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6538         gst_element_release_request_pad(element, GST_PAD(sinkpad));
6539 }
6540
6541 static gboolean
6542 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6543 {
6544         mmplayer_gst_element_t *sinkbin = NULL;
6545         main_element_id_e concatId = MMPLAYER_M_NUM;
6546         main_element_id_e sinkId = MMPLAYER_M_NUM;
6547         gboolean send_notice = FALSE;
6548         GstElement *element;
6549         GstIterator *iter;
6550
6551         MMPLAYER_FENTER();
6552         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6553
6554         LOGD("type %d", type);
6555
6556         switch (type) {
6557         case MM_PLAYER_TRACK_TYPE_AUDIO:
6558                 concatId = MMPLAYER_M_A_CONCAT;
6559                 sinkId = MMPLAYER_A_BIN;
6560                 sinkbin = player->pipeline->audiobin;
6561                 break;
6562         case MM_PLAYER_TRACK_TYPE_VIDEO:
6563                 concatId = MMPLAYER_M_V_CONCAT;
6564                 sinkId = MMPLAYER_V_BIN;
6565                 sinkbin = player->pipeline->videobin;
6566                 send_notice = TRUE;
6567                 break;
6568         case MM_PLAYER_TRACK_TYPE_TEXT:
6569                 concatId = MMPLAYER_M_T_CONCAT;
6570                 sinkId = MMPLAYER_T_BIN;
6571                 sinkbin = player->pipeline->textbin;
6572                 break;
6573         default:
6574                 LOGE("requested type is not supportable");
6575                 return FALSE;
6576                 break;
6577         }
6578
6579         element = player->pipeline->mainbin[concatId].gst;
6580         if (!element)
6581                 return TRUE;
6582
6583         if ((sinkbin) && (sinkbin[sinkId].gst)) {
6584                 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6585                 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6586                 if (srcpad && sinkpad) {
6587                         /* after getting drained signal there is no data flows, so no need to do pad_block */
6588                         LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6589                         gst_pad_unlink(srcpad, sinkpad);
6590
6591                         /* send custom event to sink pad to handle it at video sink */
6592                         if (send_notice) {
6593                                 LOGD("send custom event to sinkpad");
6594                                 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6595                                 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6596                                 gst_pad_send_event(sinkpad, event);
6597                         }
6598                 }
6599                 gst_object_unref(srcpad);
6600                 gst_object_unref(sinkpad);
6601         }
6602
6603         LOGD("release concat request pad");
6604         /* release and unref requests pad from the selector */
6605         iter = gst_element_iterate_sink_pads(element);
6606         while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6607                 gst_iterator_resync(iter);
6608         gst_iterator_free(iter);
6609
6610         return TRUE;
6611 }
6612
6613 static gboolean
6614 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6615 {
6616         mmplayer_track_t *selector = &player->track[type];
6617         mmplayer_gst_element_t *sinkbin = NULL;
6618         main_element_id_e selectorId = MMPLAYER_M_NUM;
6619         main_element_id_e sinkId = MMPLAYER_M_NUM;
6620         GstPad *srcpad = NULL;
6621         GstPad *sinkpad = NULL;
6622         gboolean send_notice = FALSE;
6623
6624         MMPLAYER_FENTER();
6625         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6626
6627         LOGD("type %d", type);
6628
6629         switch (type) {
6630         case MM_PLAYER_TRACK_TYPE_AUDIO:
6631                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6632                 sinkId = MMPLAYER_A_BIN;
6633                 sinkbin = player->pipeline->audiobin;
6634                 break;
6635         case MM_PLAYER_TRACK_TYPE_VIDEO:
6636                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6637                 sinkId = MMPLAYER_V_BIN;
6638                 sinkbin = player->pipeline->videobin;
6639                 send_notice = TRUE;
6640                 break;
6641         case MM_PLAYER_TRACK_TYPE_TEXT:
6642                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6643                 sinkId = MMPLAYER_T_BIN;
6644                 sinkbin = player->pipeline->textbin;
6645                 break;
6646         default:
6647                 LOGE("requested type is not supportable");
6648                 return FALSE;
6649                 break;
6650         }
6651
6652         if (player->pipeline->mainbin[selectorId].gst) {
6653                 gint n;
6654
6655                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6656
6657                 if (selector->event_probe_id != 0)
6658                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6659                 selector->event_probe_id = 0;
6660
6661                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6662                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6663
6664                         if (srcpad && sinkpad) {
6665                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6666                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6667                                 gst_pad_unlink(srcpad, sinkpad);
6668
6669                                 /* send custom event to sink pad to handle it at video sink */
6670                                 if (send_notice) {
6671                                         LOGD("send custom event to sinkpad");
6672                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6673                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6674                                         gst_pad_send_event(sinkpad, event);
6675                                 }
6676                         }
6677
6678                         gst_object_unref(sinkpad);
6679                         sinkpad = NULL;
6680                 }
6681                 gst_object_unref(srcpad);
6682                 srcpad = NULL;
6683
6684                 LOGD("selector release");
6685
6686                 /* release and unref requests pad from the selector */
6687                 for (n = 0; n < selector->streams->len; n++) {
6688                         GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6689                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6690                 }
6691
6692                 g_ptr_array_set_size(selector->streams, 0);
6693
6694                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6695                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6696
6697                 player->pipeline->mainbin[selectorId].gst = NULL;
6698                 selector = NULL;
6699         }
6700
6701         return TRUE;
6702 }
6703
6704 static void
6705 __mmplayer_deactivate_old_path(mmplayer_t *player)
6706 {
6707         MMPLAYER_FENTER();
6708         MMPLAYER_RETURN_IF_FAIL(player);
6709
6710         if (MMPLAYER_USE_DECODEBIN(player)) {
6711                 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6712                         (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6713                         (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6714                         LOGE("deactivate selector error");
6715                         goto ERROR;
6716                 }
6717         } else {
6718                 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6719                         (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6720                         (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6721                         LOGE("deactivate concat error");
6722                         goto ERROR;
6723                 }
6724         }
6725
6726         _mmplayer_track_destroy(player);
6727         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6728
6729         if (player->streamer) {
6730                 _mm_player_streaming_initialize(player->streamer, FALSE);
6731                 _mm_player_streaming_destroy(player->streamer);
6732                 player->streamer = NULL;
6733         }
6734
6735         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6736         MMPLAYER_FLEAVE();
6737         return;
6738
6739 ERROR:
6740
6741         if (!player->msg_posted) {
6742                 MMMessageParamType msg = {0,};
6743
6744                 /*post error*/
6745                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6746                 LOGE("gapless_uri_play> deactivate error");
6747
6748                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6749                 player->msg_posted = TRUE;
6750         }
6751         return;
6752 }
6753
6754 int
6755 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6756 {
6757         int result = MM_ERROR_NONE;
6758         mmplayer_t *player = (mmplayer_t *)hplayer;
6759         MMPLAYER_FENTER();
6760
6761         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6762         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6763
6764         if (mm_player_set_attribute(hplayer, NULL,
6765                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6766                 LOGE("failed to set attribute");
6767                 result = MM_ERROR_PLAYER_INTERNAL;
6768         } else {
6769                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6770                         LOGE("failed to add the original uri in the uri list.");
6771         }
6772
6773         MMPLAYER_FLEAVE();
6774         return result;
6775 }
6776
6777 int
6778 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6779 {
6780         mmplayer_t *player = (mmplayer_t *)hplayer;
6781         guint num_of_list = 0;
6782
6783         MMPLAYER_FENTER();
6784
6785         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6786         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6787
6788         if (player->pipeline && player->pipeline->textbin) {
6789                 LOGE("subtitle path is enabled.");
6790                 return MM_ERROR_PLAYER_INVALID_STATE;
6791         }
6792
6793         num_of_list = g_list_length(player->uri_info.uri_list);
6794
6795         if (is_first_path) {
6796                 if (num_of_list == 0) {
6797                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6798                         SECURE_LOGD("add original path : %s", uri);
6799                 } else {
6800                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6801                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6802
6803                         SECURE_LOGD("change original path : %s", uri);
6804                 }
6805         } else {
6806                 MMHandleType attrs = 0;
6807                 attrs = MMPLAYER_GET_ATTRS(player);
6808
6809                 if (num_of_list == 0) {
6810                         char *original_uri = NULL;
6811
6812                         if (attrs) {
6813                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6814
6815                                 if (!original_uri) {
6816                                         LOGE("there is no original uri.");
6817                                         return MM_ERROR_PLAYER_INVALID_STATE;
6818                                 }
6819
6820                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6821                                 player->uri_info.uri_idx = 0;
6822
6823                                 SECURE_LOGD("add original path at first : %s", original_uri);
6824                         }
6825                 }
6826
6827                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6828                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6829         }
6830
6831         MMPLAYER_FLEAVE();
6832         return MM_ERROR_NONE;
6833 }
6834
6835 int
6836 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6837 {
6838         mmplayer_t *player = (mmplayer_t *)hplayer;
6839         char *next_uri = NULL;
6840         guint num_of_list = 0;
6841
6842         MMPLAYER_FENTER();
6843         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6844
6845         num_of_list = g_list_length(player->uri_info.uri_list);
6846
6847         if (num_of_list > 0) {
6848                 gint uri_idx = player->uri_info.uri_idx;
6849
6850                 if (uri_idx < num_of_list - 1)
6851                         uri_idx++;
6852                 else
6853                         uri_idx = 0;
6854
6855                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6856                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6857
6858                 *uri = g_strdup(next_uri);
6859         }
6860
6861         MMPLAYER_FLEAVE();
6862         return MM_ERROR_NONE;
6863 }
6864
6865 void
6866 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6867         GstCaps *caps, gpointer data)
6868 {
6869         mmplayer_t *player = (mmplayer_t *)data;
6870         const gchar *klass = NULL;
6871         const gchar *mime = NULL;
6872         gchar *caps_str = NULL;
6873
6874         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6875         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6876         caps_str = gst_caps_to_string(caps);
6877
6878         LOGW("unknown type of caps : %s from %s",
6879                                         caps_str, GST_ELEMENT_NAME(elem));
6880
6881         MMPLAYER_FREEIF(caps_str);
6882
6883         /* There is no available codec. */
6884         __mmplayer_check_not_supported_codec(player, klass, mime);
6885 }
6886
6887 gboolean
6888 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6889         GstCaps *caps, gpointer data)
6890 {
6891         mmplayer_t *player = (mmplayer_t *)data;
6892         const char *mime = NULL;
6893         gboolean ret = TRUE;
6894
6895         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6896         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6897
6898         if (g_str_has_prefix(mime, "audio")) {
6899                 GstStructure *caps_structure = NULL;
6900                 gint samplerate = 0;
6901                 gint channels = 0;
6902                 gchar *caps_str = NULL;
6903
6904                 caps_structure = gst_caps_get_structure(caps, 0);
6905                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6906                 gst_structure_get_int(caps_structure, "channels", &channels);
6907
6908                 if ((channels > 0 && samplerate == 0)) {
6909                         LOGD("exclude audio...");
6910                         ret = FALSE;
6911                 }
6912
6913                 caps_str = gst_caps_to_string(caps);
6914                 /* set it directly because not sent by TAG */
6915                 if (g_strrstr(caps_str, "mobile-xmf"))
6916                         mm_player_set_attribute((MMHandleType)player, NULL,
6917                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6918
6919                 MMPLAYER_FREEIF(caps_str);
6920         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6921                 LOGD("already video linked");
6922                 ret = FALSE;
6923         } else {
6924                 LOGD("found new stream");
6925         }
6926
6927         return ret;
6928 }
6929
6930 static gboolean
6931 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6932 {
6933         gboolean ret = FALSE;
6934         GDBusConnection *conn = NULL;
6935         GError *err = NULL;
6936         GVariant *result = NULL;
6937         const gchar *dbus_device_type = NULL;
6938         const gchar *dbus_ret = NULL;
6939         gint idx = 0;
6940
6941         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6942         if (!conn || err) {
6943                 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6944                 g_error_free(err);
6945                 goto DONE;
6946         }
6947
6948         result = g_dbus_connection_call_sync(conn,
6949                                         "org.pulseaudio.Server",
6950                                         "/org/pulseaudio/StreamManager",
6951                                         "org.pulseaudio.StreamManager",
6952                                         "GetCurrentMediaRoutingPath",
6953                                         g_variant_new("(s)", "out"),
6954                                         G_VARIANT_TYPE("(ss)"),
6955                                         G_DBUS_CALL_FLAGS_NONE,
6956                                         2000,
6957                                         NULL,
6958                                         &err);
6959         if (!result || err) {
6960                 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6961                 g_error_free(err);
6962                 goto DONE;
6963         }
6964
6965         /* device type is listed in stream-map.json at mmfw-sysconf */
6966         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6967
6968         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6969         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6970                 goto DONE;
6971
6972         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6973         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6974                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6975                         LOGD("audio offload is supportable");
6976                         ret = TRUE;
6977                         goto DONE;
6978                 }
6979         }
6980
6981         LOGD("audio offload is not supportable");
6982
6983 DONE:
6984         g_variant_unref(result);
6985         if (conn)
6986                 g_object_unref(conn);
6987
6988         return ret;
6989 }
6990
6991 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6992 {
6993         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6994         gint64 position = 0;
6995
6996         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6997                 player->pipeline && player->pipeline->mainbin);
6998
6999         MMPLAYER_CMD_LOCK(player);
7000         current_state = MMPLAYER_CURRENT_STATE(player);
7001
7002         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7003                 LOGW("getting current position failed in paused");
7004
7005         _mmplayer_unrealize((MMHandleType)player);
7006         _mmplayer_realize((MMHandleType)player);
7007
7008         _mmplayer_set_position((MMHandleType)player, position);
7009
7010         /* async not to be blocked in streaming case */
7011         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7012
7013         _mmplayer_pause((MMHandleType)player);
7014
7015         if (current_state == MM_PLAYER_STATE_PLAYING)
7016                 _mmplayer_start((MMHandleType)player);
7017         MMPLAYER_CMD_UNLOCK(player);
7018
7019         LOGD("rebuilding audio pipeline is completed.");
7020 }
7021
7022 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7023 {
7024         mmplayer_t *player = (mmplayer_t *)user_data;
7025         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7026         gboolean is_supportable = FALSE;
7027
7028         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7029                 LOGW("failed to get device type");
7030         else
7031                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7032
7033         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7034                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7035                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7036                 LOGD("ignore this dev connected info");
7037                 return;
7038         }
7039
7040         is_supportable = __mmplayer_is_audio_offload_device_type(player);
7041         if (player->build_audio_offload == is_supportable) {
7042                 LOGD("keep current pipeline without re-building");
7043                 return;
7044         }
7045
7046         /* rebuild pipeline */
7047         LOGD("re-build pipeline - offload: %d", is_supportable);
7048         player->build_audio_offload = FALSE;
7049         __mmplayer_rebuild_audio_pipeline(player);
7050
7051         return;
7052 }
7053
7054 static gboolean
7055 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7056 {
7057         unsigned int id = 0;
7058
7059         if (player->audio_device_cb_id != 0) {
7060                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7061                 return TRUE;
7062         }
7063
7064         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7065                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7066                 LOGD("added device connected cb (%u)", id);
7067                 player->audio_device_cb_id = id;
7068         } else {
7069                 LOGW("failed to add device connected cb");
7070                 return FALSE;
7071         }
7072
7073         return TRUE;
7074 }
7075
7076 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7077 {
7078         mmplayer_t *player = (mmplayer_t *)hplayer;
7079
7080         MMPLAYER_FENTER();
7081         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7082         MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7083
7084         *activated = player->build_audio_offload;
7085
7086         LOGD("offload activated : %d", (int)*activated);
7087
7088         MMPLAYER_FLEAVE();
7089         return MM_ERROR_NONE;
7090 }
7091
7092 static gboolean
7093 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7094 {
7095         /* NOTE :
7096            this function need to be updated according to the supported media format
7097            @see player->ini.audio_offload_media_format */
7098
7099         if (__mmplayer_is_only_mp3_type(player->type)) {
7100                 LOGD("offload supportable media format type");
7101                 return TRUE;
7102         }
7103
7104         return FALSE;
7105 }
7106
7107 static gboolean
7108 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7109 {
7110         gboolean ret = FALSE;
7111         GstElementFactory *factory = NULL;
7112
7113         MMPLAYER_FENTER();
7114         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7115
7116         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7117         if (!__mmplayer_is_offload_supported_type(player))
7118                 goto DONE;
7119
7120         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7121                 LOGD("there is no audio offload sink");
7122                 goto DONE;
7123         }
7124
7125         if (player->ini.audio_offload_device_type[0][0] == '\0') {
7126                 LOGW("there is no audio device type to support offload");
7127                 goto DONE;
7128         }
7129
7130         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7131         if (!factory) {
7132                 LOGW("there is no installed audio offload sink element");
7133                 goto DONE;
7134         }
7135         gst_object_unref(factory);
7136
7137         if (_mmplayer_acquire_hw_resource(player,
7138                         MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7139                 LOGE("failed to acquire audio offload decoder resource");
7140                 goto DONE;
7141         }
7142
7143         if (!__mmplayer_add_audio_device_connected_cb(player))
7144                 goto DONE;
7145
7146         if (!__mmplayer_is_audio_offload_device_type(player))
7147                 goto DONE;
7148
7149         LOGD("audio offload can be built");
7150         ret = TRUE;
7151
7152 DONE:
7153         if (!ret)
7154                 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7155
7156         MMPLAYER_FLEAVE();
7157         return ret;
7158 }
7159
7160 static GstAutoplugSelectResult
7161 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7162 {
7163         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7164         int audio_offload = 0;
7165
7166         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7167                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7168
7169                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7170                         LOGD("expose audio path to build offload output path");
7171                         player->build_audio_offload = TRUE;
7172                         /* update codec info */
7173                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7174                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7175                         player->audiodec_linked = 1;
7176
7177                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
7178                         goto DONE;
7179                 }
7180
7181                 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7182                                   And need to consider the multi-track audio content.
7183                           There is no HW audio decoder in public. */
7184
7185                 /* set stream information */
7186                 if (!player->audiodec_linked)
7187                         _mmplayer_set_audio_attrs(player, caps);
7188
7189                 /* update codec info */
7190                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7191                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7192                 player->audiodec_linked = 1;
7193
7194         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7195
7196                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7197                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7198
7199                         /* mark video decoder for acquire */
7200                         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7201                                 LOGW("video decoder resource is already acquired, skip it.");
7202                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7203                                 goto DONE;
7204                         }
7205
7206                         if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7207                                 LOGE("failed to acquire video decoder resource");
7208                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7209                                 goto DONE;
7210                         }
7211                         player->interrupted_by_resource = FALSE;
7212                 }
7213
7214                 /* update codec info */
7215                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7216                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7217                 player->videodec_linked = 1;
7218         }
7219
7220 DONE:
7221         return ret;
7222 }
7223
7224 GValueArray *
7225 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7226                 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7227 {
7228 #define DEFAULT_IDX 0xFFFF
7229 #define MIN_FACTORY_NUM 2
7230         mmplayer_t *player = (mmplayer_t *)data;
7231         GValueArray *new_factories = NULL;
7232         GValue val = { 0, };
7233         GstElementFactory *factory = NULL;
7234         const gchar *klass = NULL;
7235         gchar *factory_name = NULL;
7236         guint hw_dec_idx = DEFAULT_IDX;
7237         guint first_sw_dec_idx = DEFAULT_IDX;
7238         guint last_sw_dec_idx = DEFAULT_IDX;
7239         guint new_pos = DEFAULT_IDX;
7240         guint rm_pos = DEFAULT_IDX;
7241         int audio_codec_type;
7242         int video_codec_type;
7243         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7244
7245         if (factories->n_values < MIN_FACTORY_NUM)
7246                 return NULL;
7247
7248         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7249         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7250
7251 #ifdef __DEBUG__
7252         LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7253 #endif
7254         for (int i = 0 ; i < factories->n_values ; i++) {
7255                 gchar *hw_dec_info = NULL;
7256                 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7257
7258                 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7259                 if (!factory) {
7260                         LOGW("failed to get factory object");
7261                         continue;
7262                 }
7263                 klass = gst_element_factory_get_klass(factory);
7264                 factory_name = GST_OBJECT_NAME(factory);
7265
7266 #ifdef __DEBUG__
7267                 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7268 #endif
7269                 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7270                         if (!player->need_audio_dec_sorting) {
7271                                 LOGD("sorting is not required");
7272                                 return NULL;
7273                         }
7274                         codec_type = audio_codec_type;
7275                         hw_dec_info = player->ini.audiocodec_element_hw;
7276                         sw_dec_info = player->ini.audiocodec_element_sw;
7277                 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7278                         if (!player->need_video_dec_sorting) {
7279                                 LOGD("sorting is not required");
7280                                 return NULL;
7281                         }
7282                         codec_type = video_codec_type;
7283                         hw_dec_info = player->ini.videocodec_element_hw;
7284                         sw_dec_info = player->ini.videocodec_element_sw;
7285                 } else {
7286                         continue;
7287                 }
7288
7289                 if (g_strrstr(factory_name, hw_dec_info)) {
7290                         hw_dec_idx = i;
7291                 } else {
7292                         for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7293                                 if (strstr(factory_name, sw_dec_info[j])) {
7294                                         last_sw_dec_idx = i;
7295                                         if (first_sw_dec_idx == DEFAULT_IDX) {
7296                                                 first_sw_dec_idx = i;
7297                                         }
7298                                 }
7299                         }
7300
7301                         if (first_sw_dec_idx == DEFAULT_IDX)
7302                                 LOGW("unknown codec %s", factory_name);
7303                 }
7304         }
7305
7306         if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7307                 return NULL;
7308
7309         if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7310                 if (hw_dec_idx < first_sw_dec_idx)
7311                         return NULL;
7312                 new_pos = first_sw_dec_idx;
7313                 rm_pos = hw_dec_idx + 1;
7314         } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7315                 if (last_sw_dec_idx < hw_dec_idx)
7316                         return NULL;
7317                 new_pos = last_sw_dec_idx + 1;
7318                 rm_pos = hw_dec_idx;
7319         } else {
7320                 return NULL;
7321         }
7322
7323         /* change position - insert H/W decoder according to the new position */
7324         factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7325         if (!factory) {
7326                 LOGW("failed to get factory object");
7327                 return NULL;
7328         }
7329         new_factories = g_value_array_copy(factories);
7330         g_value_init (&val, G_TYPE_OBJECT);
7331         g_value_set_object (&val, factory);
7332         g_value_array_insert(new_factories, new_pos, &val);
7333         g_value_unset (&val);
7334         g_value_array_remove(new_factories, rm_pos);    /* remove previous H/W element */
7335
7336         for (int i = 0 ; i < new_factories->n_values ; i++) {
7337                 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7338                 if (factory)
7339                         LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7340                                 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7341                 else
7342                         LOGE("[Re-arranged] failed to get factory object");
7343         }
7344
7345         return new_factories;
7346 }
7347
7348 gint
7349 _mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7350         GstCaps *caps, GstElementFactory *factory, gpointer data)
7351 {
7352         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7353         mmplayer_t *player = (mmplayer_t *)data;
7354
7355         gchar *factory_name = NULL;
7356         gchar *caps_str = NULL;
7357         const gchar *klass = NULL;
7358         gint idx = 0;
7359
7360         factory_name = GST_OBJECT_NAME(factory);
7361         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7362         caps_str = gst_caps_to_string(caps);
7363
7364         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7365
7366         /* store type string */
7367         if (player->type == NULL) {
7368                 player->type = gst_caps_to_string(caps);
7369                 __mmplayer_update_content_type_info(player);
7370         }
7371
7372         /* filtering exclude keyword */
7373         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7374                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7375                         LOGW("skipping [%s] by exculde keyword [%s]",
7376                                         factory_name, player->ini.exclude_element_keyword[idx]);
7377
7378                         result = GST_AUTOPLUG_SELECT_SKIP;
7379                         goto DONE;
7380                 }
7381         }
7382
7383         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7384                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7385                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7386                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7387                         result = GST_AUTOPLUG_SELECT_SKIP;
7388                         goto DONE;
7389                 }
7390         }
7391
7392         /* exclude webm format */
7393         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7394          * because webm format is not supportable.
7395          * If webm is disabled in "autoplug-continue", there is no state change
7396          * failure or error because the decodebin will expose the pad directly.
7397          * It make MSL invoke _prepare_async_callback.
7398          * So, we need to disable webm format in "autoplug-select" */
7399         if (caps_str && strstr(caps_str, "webm")) {
7400                 LOGW("webm is not supported");
7401                 result = GST_AUTOPLUG_SELECT_SKIP;
7402                 goto DONE;
7403         }
7404
7405         /* check factory class for filtering */
7406         /* NOTE : msl don't need to use image plugins.
7407          * So, those plugins should be skipped for error handling.
7408          */
7409         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7410                 LOGD("skipping [%s] by not required", factory_name);
7411                 result = GST_AUTOPLUG_SELECT_SKIP;
7412                 goto DONE;
7413         }
7414
7415         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7416                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7417                 // TO CHECK : subtitle if needed, add subparse exception.
7418                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7419                 result = GST_AUTOPLUG_SELECT_SKIP;
7420                 goto DONE;
7421         }
7422
7423         if (g_strrstr(factory_name, "mpegpsdemux")) {
7424                 LOGD("skipping PS container - not support");
7425                 result = GST_AUTOPLUG_SELECT_SKIP;
7426                 goto DONE;
7427         }
7428
7429         if (g_strrstr(factory_name, "mssdemux"))
7430                 player->smooth_streaming = TRUE;
7431
7432         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7433                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7434                 gint stype = 0;
7435                 gint width = 0;
7436                 GstStructure *str = NULL;
7437                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7438
7439                 /* don't make video because of not required */
7440                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7441                         (!player->set_mode.video_export)) {
7442                         LOGD("no need video decoding, expose pad");
7443                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7444                         goto DONE;
7445                 }
7446
7447                 /* get w/h for omx state-tune */
7448                 /* FIXME: deprecated? */
7449                 str = gst_caps_get_structure(caps, 0);
7450                 gst_structure_get_int(str, "width", &width);
7451
7452                 if (width != 0) {
7453                         if (player->v_stream_caps) {
7454                                 gst_caps_unref(player->v_stream_caps);
7455                                 player->v_stream_caps = NULL;
7456                         }
7457
7458                         player->v_stream_caps = gst_caps_copy(caps);
7459                         LOGD("take caps for video state tune");
7460                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7461                 }
7462         }
7463
7464         if (g_strrstr(klass, "Codec/Decoder")) {
7465                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7466                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7467                         LOGW("skip add decoder");
7468                         goto DONE;
7469                 }
7470         }
7471
7472 DONE:
7473         MMPLAYER_FREEIF(caps_str);
7474
7475         return result;
7476 }
7477
7478 void
7479 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7480         gpointer data)
7481 {
7482         //mmplayer_t *player = (mmplayer_t *)data;
7483         GstCaps *caps = NULL;
7484
7485         LOGD("[Decodebin2] pad-removed signal");
7486
7487         caps = gst_pad_query_caps(new_pad, NULL);
7488         if (!caps) {
7489                 LOGW("query caps is NULL");
7490                 return;
7491         }
7492
7493         gchar *caps_str = NULL;
7494         caps_str = gst_caps_to_string(caps);
7495
7496         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7497
7498         MMPLAYER_FREEIF(caps_str);
7499         gst_caps_unref(caps);
7500 }
7501
7502 void
7503 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7504 {
7505         mmplayer_t *player = (mmplayer_t *)data;
7506
7507         MMPLAYER_FENTER();
7508         MMPLAYER_RETURN_IF_FAIL(player);
7509
7510         LOGD("got about to finish signal");
7511
7512         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7513                 LOGW("Fail to get cmd lock");
7514                 return;
7515         }
7516
7517         if (!__mmplayer_verify_gapless_play_path(player)) {
7518                 LOGD("decoding is finished.");
7519                 MMPLAYER_CMD_UNLOCK(player);
7520                 return;
7521         }
7522
7523         _mmplayer_set_reconfigure_state(player, TRUE);
7524         MMPLAYER_CMD_UNLOCK(player);
7525
7526         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7527         __mmplayer_deactivate_old_path(player);
7528
7529         MMPLAYER_FLEAVE();
7530 }
7531
7532 void
7533 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7534 {
7535         mmplayer_t *player = (mmplayer_t *)data;
7536         GstIterator *iter = NULL;
7537         GValue item = { 0, };
7538         GstPad *pad = NULL;
7539         gboolean done = FALSE;
7540         gboolean is_all_drained = TRUE;
7541
7542         MMPLAYER_FENTER();
7543         MMPLAYER_RETURN_IF_FAIL(player);
7544
7545         LOGD("got drained signal");
7546
7547         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7548                 LOGW("Fail to get cmd lock");
7549                 return;
7550         }
7551
7552         if (!__mmplayer_verify_gapless_play_path(player)) {
7553                 LOGD("decoding is finished.");
7554                 MMPLAYER_CMD_UNLOCK(player);
7555                 return;
7556         }
7557
7558         _mmplayer_set_reconfigure_state(player, TRUE);
7559         MMPLAYER_CMD_UNLOCK(player);
7560
7561         /* check decodebin src pads whether they received EOS or not */
7562         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7563
7564         while (!done) {
7565                 switch (gst_iterator_next(iter, &item)) {
7566                 case GST_ITERATOR_OK:
7567                         pad = g_value_get_object(&item);
7568                         if (pad && !GST_PAD_IS_EOS(pad)) {
7569                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7570                                 is_all_drained = FALSE;
7571                                 break;
7572                         }
7573                         g_value_reset(&item);
7574                         break;
7575                 case GST_ITERATOR_RESYNC:
7576                         gst_iterator_resync(iter);
7577                         break;
7578                 case GST_ITERATOR_ERROR:
7579                 case GST_ITERATOR_DONE:
7580                         done = TRUE;
7581                         break;
7582                 }
7583         }
7584         g_value_unset(&item);
7585         gst_iterator_free(iter);
7586
7587         if (!is_all_drained) {
7588                 LOGD("Wait util the all pads get EOS.");
7589                 MMPLAYER_FLEAVE();
7590                 return;
7591         }
7592
7593         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7594         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7595
7596         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7597         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7598         __mmplayer_deactivate_old_path(player);
7599
7600         MMPLAYER_FLEAVE();
7601 }
7602
7603 void
7604 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7605 {
7606         mmplayer_t *player = (mmplayer_t *)data;
7607         const gchar *klass = NULL;
7608         gchar *factory_name = NULL;
7609
7610         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7611         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7612
7613         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7614
7615         if (__mmplayer_add_dump_buffer_probe(player, element))
7616                 LOGD("add buffer probe");
7617
7618         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7619                 gchar *selected = NULL;
7620                 selected = g_strdup(GST_ELEMENT_NAME(element));
7621                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7622
7623                 /* update codec info */
7624                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7625                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7626                 player->audiodec_linked = 1;
7627         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7628                 /* update codec info */
7629                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7630                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7631                 player->videodec_linked = 1;
7632         }
7633
7634         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7635                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7636                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7637
7638                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7639                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7640
7641                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7642                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7643                                                 "max-video-width", player->adaptive_info.limit.width,
7644                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7645
7646         } else if (g_strrstr(klass, "Demuxer")) {
7647 #ifdef __DEBUG__
7648                 LOGD("plugged element is demuxer. take it");
7649 #endif
7650                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7651                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7652         }
7653
7654         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7655                 int surface_type = 0;
7656
7657                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7658         }
7659
7660         // to support trust-zone only
7661         if (g_strrstr(factory_name, "asfdemux")) {
7662                 LOGD("set file-location %s", player->profile.uri);
7663                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7664         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7665                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7666                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7667         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7668                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7669                         (__mmplayer_is_only_mp3_type(player->type))) {
7670                         LOGD("[mpegaudioparse] set streaming pull mode.");
7671                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7672                 }
7673         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7674                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7675         }
7676
7677         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7678                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7679                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7680
7681                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7682                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7683
7684                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7685                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7686                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7687                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7688                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7689                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7690                 }
7691
7692         }
7693
7694         return;
7695 }
7696
7697 static void
7698 __mmplayer_release_misc(mmplayer_t *player)
7699 {
7700         int i;
7701         bool cur_mode = player->set_mode.rich_audio;
7702         MMPLAYER_FENTER();
7703
7704         MMPLAYER_RETURN_IF_FAIL(player);
7705
7706         player->sent_bos = FALSE;
7707         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7708
7709         player->seek_state = MMPLAYER_SEEK_NONE;
7710
7711         player->total_bitrate = 0;
7712         player->total_maximum_bitrate = 0;
7713
7714         player->not_found_demuxer = 0;
7715
7716         player->last_position = 0;
7717         player->duration = 0;
7718         player->http_content_size = 0;
7719         player->not_supported_codec = MISSING_PLUGIN_NONE;
7720         player->can_support_codec = FOUND_PLUGIN_NONE;
7721         player->pending_seek.is_pending = false;
7722         player->pending_seek.pos = 0;
7723         player->msg_posted = FALSE;
7724         player->has_many_types = FALSE;
7725         player->is_subtitle_force_drop = FALSE;
7726         player->play_subtitle = FALSE;
7727         player->adjust_subtitle_pos = 0;
7728         player->has_closed_caption = FALSE;
7729         player->set_mode.video_export = false;
7730         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7731         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7732         /* recover mode */
7733         player->set_mode.rich_audio = cur_mode;
7734
7735         if (player->audio_device_cb_id > 0 &&
7736                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7737                 LOGW("failed to remove audio device_connected_callback");
7738         player->audio_device_cb_id = 0;
7739
7740         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7741                 player->bitrate[i] = 0;
7742                 player->maximum_bitrate[i] = 0;
7743         }
7744
7745         /* free memory related to audio effect */
7746         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7747
7748         if (player->adaptive_info.var_list) {
7749                 g_list_free_full(player->adaptive_info.var_list, g_free);
7750                 player->adaptive_info.var_list = NULL;
7751         }
7752
7753         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7754         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7755         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7756
7757         /* Reset video360 settings to their defaults in case if the pipeline is to be
7758          * re-created.
7759          * */
7760         player->video360_metadata.is_spherical = -1;
7761         player->is_openal_plugin_used = FALSE;
7762
7763         player->is_content_spherical = FALSE;
7764         player->is_video360_enabled = TRUE;
7765         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7766         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7767         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7768         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7769         player->video360_zoom = 1.0f;
7770         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7771         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7772
7773         player->sound.rg_enable = false;
7774
7775         __mmplayer_initialize_video_roi(player);
7776         MMPLAYER_FLEAVE();
7777 }
7778
7779 static void
7780 __mmplayer_release_misc_post(mmplayer_t *player)
7781 {
7782         char *original_uri = NULL;
7783         MMPLAYER_FENTER();
7784
7785         /* player->pipeline is already released before. */
7786         MMPLAYER_RETURN_IF_FAIL(player);
7787
7788         player->video_decoded_cb = NULL;
7789         player->video_decoded_cb_user_param = NULL;
7790         player->video_stream_prerolled = false;
7791
7792         player->audio_decoded_cb = NULL;
7793         player->audio_decoded_cb_user_param = NULL;
7794         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7795
7796         player->audio_stream_changed_cb = NULL;
7797         player->audio_stream_changed_cb_user_param = NULL;
7798
7799         mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7800
7801         /* clean found audio decoders */
7802         if (player->audio_decoders) {
7803                 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7804                 player->audio_decoders = NULL;
7805         }
7806
7807         /* clean the uri list except original uri */
7808         if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7809                 GList *tmp = NULL;
7810                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7811                 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7812                 g_list_free_full(tmp, (GDestroyNotify)g_free);
7813
7814                 if (!original_uri)
7815                         LOGW("failed to get original uri info");
7816
7817                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7818                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7819
7820         }
7821
7822         /* clear the audio stream buffer list */
7823         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7824
7825         /* clear the video stream bo list */
7826         __mmplayer_video_stream_destroy_bo_list(player);
7827         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7828
7829         if (player->profile.input_mem.buf) {
7830                 free(player->profile.input_mem.buf);
7831                 player->profile.input_mem.buf = NULL;
7832         }
7833         player->profile.input_mem.len = 0;
7834         player->profile.input_mem.offset = 0;
7835
7836         player->uri_info.uri_idx = 0;
7837         MMPLAYER_FLEAVE();
7838 }
7839
7840 gboolean
7841 __mmplayer_check_subtitle(mmplayer_t *player)
7842 {
7843         MMHandleType attrs = 0;
7844         char *subtitle_uri = NULL;
7845
7846         MMPLAYER_FENTER();
7847
7848         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7849
7850         /* get subtitle attribute */
7851         attrs = MMPLAYER_GET_ATTRS(player);
7852         if (!attrs)
7853                 return FALSE;
7854
7855         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7856         if (!subtitle_uri || !strlen(subtitle_uri))
7857                 return FALSE;
7858
7859         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7860         player->is_external_subtitle_present = TRUE;
7861
7862         MMPLAYER_FLEAVE();
7863
7864         return TRUE;
7865 }
7866
7867 void
7868 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7869 {
7870         MMPLAYER_RETURN_IF_FAIL(player);
7871
7872         if (player->eos_timer) {
7873                 LOGD("cancel eos timer");
7874                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7875                 player->eos_timer = 0;
7876         }
7877
7878         return;
7879 }
7880
7881 static void
7882 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7883 {
7884         MMPLAYER_FENTER();
7885
7886         MMPLAYER_RETURN_IF_FAIL(player);
7887         MMPLAYER_RETURN_IF_FAIL(sink);
7888
7889         if (first)
7890                 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7891         else
7892                 player->sink_elements = g_list_append(player->sink_elements, sink);
7893
7894         MMPLAYER_FLEAVE();
7895 }
7896
7897 static void
7898 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7899 {
7900         MMPLAYER_FENTER();
7901
7902         MMPLAYER_RETURN_IF_FAIL(player);
7903         MMPLAYER_RETURN_IF_FAIL(sink);
7904
7905         player->sink_elements = g_list_remove(player->sink_elements, sink);
7906
7907         MMPLAYER_FLEAVE();
7908 }
7909
7910 void
7911 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7912         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7913 {
7914         mmplayer_signal_item_t *item = NULL;
7915
7916         MMPLAYER_FENTER();
7917         MMPLAYER_RETURN_IF_FAIL(player);
7918
7919         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7920                 LOGE("invalid signal type [%d]", type);
7921                 return;
7922         }
7923
7924         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7925         if (!item) {
7926                 LOGE("cannot connect signal [%s]", signal);
7927                 return;
7928         }
7929
7930         item->obj = object;
7931         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7932         player->signals[type] = g_list_append(player->signals[type], item);
7933
7934         MMPLAYER_FLEAVE();
7935         return;
7936 }
7937
7938 /* NOTE : be careful with calling this api. please refer to below glib comment
7939  * glib comment : Note that there is a bug in GObject that makes this function much
7940  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7941  * will no longer be called, but, the signal handler is not currently disconnected.
7942  * If the instance is itself being freed at the same time than this doesn't matter,
7943  * since the signal will automatically be removed, but if instance persists,
7944  * then the signal handler will leak. You should not remove the signal yourself
7945  * because in a future versions of GObject, the handler will automatically be
7946  * disconnected.
7947  *
7948  * It's possible to work around this problem in a way that will continue to work
7949  * with future versions of GObject by checking that the signal handler is still
7950  * connected before disconnected it:
7951  *
7952  *  if (g_signal_handler_is_connected(instance, id))
7953  *    g_signal_handler_disconnect(instance, id);
7954  */
7955 static void
7956 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7957 {
7958         GList *sig_list = NULL;
7959         mmplayer_signal_item_t *item = NULL;
7960
7961         MMPLAYER_FENTER();
7962
7963         MMPLAYER_RETURN_IF_FAIL(player);
7964
7965         LOGD("release signals type : %d", type);
7966
7967         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7968                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7969                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7970                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7971                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7972                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7973                 return;
7974         }
7975
7976         sig_list = player->signals[type];
7977
7978         for (; sig_list; sig_list = sig_list->next) {
7979                 item = sig_list->data;
7980
7981                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7982                         if (g_signal_handler_is_connected(item->obj, item->sig))
7983                                 g_signal_handler_disconnect(item->obj, item->sig);
7984                 }
7985
7986                 MMPLAYER_FREEIF(item);
7987         }
7988
7989         g_list_free(player->signals[type]);
7990         player->signals[type] = NULL;
7991
7992         MMPLAYER_FLEAVE();
7993
7994         return;
7995 }
7996
7997 int
7998 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7999 {
8000         mmplayer_t *player = 0;
8001         int prev_display_surface_type = 0;
8002
8003         MMPLAYER_FENTER();
8004
8005         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8006
8007         player = MM_PLAYER_CAST(handle);
8008
8009         /* check video sinkbin is created */
8010         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8011                 LOGW("Videosink is already created");
8012                 return MM_ERROR_NONE;
8013         }
8014
8015         LOGD("videosink element is not yet ready");
8016
8017         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8018                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8019                 MMPLAYER_FLEAVE();
8020                 return MM_ERROR_INVALID_ARGUMENT;
8021         }
8022
8023         /* load previous attributes */
8024         if (player->attrs) {
8025                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8026                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8027                 if (prev_display_surface_type == surface_type) {
8028                         LOGD("incoming display surface type is same as previous one, do nothing..");
8029                         MMPLAYER_FLEAVE();
8030                         return MM_ERROR_NONE;
8031                 }
8032         } else {
8033                 LOGE("failed to load attributes");
8034                 MMPLAYER_FLEAVE();
8035                 return MM_ERROR_PLAYER_INTERNAL;
8036         }
8037
8038         /* videobin is not created yet, so we just set attributes related to display surface */
8039         LOGD("store display attribute for given surface type(%d)", surface_type);
8040         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8041                         "display_overlay", wl_surface_id, NULL);
8042
8043         MMPLAYER_FLEAVE();
8044         return MM_ERROR_NONE;
8045 }
8046
8047 /* Note : if silent is true, then subtitle would not be displayed. :*/
8048 int
8049 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8050 {
8051         mmplayer_t *player = (mmplayer_t *)hplayer;
8052
8053         MMPLAYER_FENTER();
8054
8055         /* check player handle */
8056         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8057
8058         player->set_mode.subtitle_off = silent;
8059
8060         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8061
8062         MMPLAYER_FLEAVE();
8063
8064         return MM_ERROR_NONE;
8065 }
8066
8067 int
8068 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8069 {
8070         mmplayer_gst_element_t *mainbin = NULL;
8071         mmplayer_gst_element_t *textbin = NULL;
8072         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8073         GstState current_state = GST_STATE_VOID_PENDING;
8074         GstState element_state = GST_STATE_VOID_PENDING;
8075         GstState element_pending_state = GST_STATE_VOID_PENDING;
8076         gint64 time = 0;
8077         GstEvent *event = NULL;
8078         int result = MM_ERROR_NONE;
8079
8080         GstClock *curr_clock = NULL;
8081         GstClockTime base_time, start_time, curr_time;
8082
8083
8084         MMPLAYER_FENTER();
8085
8086         /* check player handle */
8087         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8088                                                                 player->pipeline &&
8089                                                                 player->pipeline->mainbin &&
8090                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8091
8092         mainbin = player->pipeline->mainbin;
8093         textbin = player->pipeline->textbin;
8094
8095         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8096
8097         // sync clock with current pipeline
8098         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8099         curr_time = gst_clock_get_time(curr_clock);
8100
8101         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8102         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8103
8104         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8105                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8106
8107         if (current_state > GST_STATE_READY) {
8108                 // sync state with current pipeline
8109                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8110                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8111                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8112
8113                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8114                 if (GST_STATE_CHANGE_FAILURE == ret) {
8115                         LOGE("fail to state change.");
8116                         result = MM_ERROR_PLAYER_INTERNAL;
8117                         goto ERROR;
8118                 }
8119         }
8120         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8121         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8122
8123         if (curr_clock) {
8124                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8125                 gst_object_unref(curr_clock);
8126         }
8127
8128         // seek to current position
8129         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8130                 result = MM_ERROR_PLAYER_INVALID_STATE;
8131                 LOGE("gst_element_query_position failed, invalid state");
8132                 goto ERROR;
8133         }
8134
8135         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8136         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);
8137         if (event) {
8138                 _mmplayer_gst_send_event_to_sink(player, event);
8139         } else {
8140                 result = MM_ERROR_PLAYER_INTERNAL;
8141                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8142                 goto ERROR;
8143         }
8144
8145         /* sync state with current pipeline */
8146         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8147         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8148         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8149
8150         return MM_ERROR_NONE;
8151
8152 ERROR:
8153         /* release text pipeline resource */
8154         player->textsink_linked = 0;
8155
8156         /* release signal */
8157         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8158
8159         /* release textbin with it's childs */
8160         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8161         MMPLAYER_FREEIF(player->pipeline->textbin);
8162         player->pipeline->textbin = NULL;
8163
8164         /* release subtitle elem */
8165         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8166         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8167
8168         return result;
8169 }
8170
8171 static int
8172 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8173 {
8174         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8175         GstState current_state = GST_STATE_VOID_PENDING;
8176
8177         MMHandleType attrs = 0;
8178         mmplayer_gst_element_t *mainbin = NULL;
8179         mmplayer_gst_element_t *textbin = NULL;
8180
8181         gchar *subtitle_uri = NULL;
8182         int result = MM_ERROR_NONE;
8183         const gchar *charset = NULL;
8184
8185         MMPLAYER_FENTER();
8186
8187         /* check player handle */
8188         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8189                                                                 player->pipeline &&
8190                                                                 player->pipeline->mainbin &&
8191                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8192         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8193
8194         mainbin = player->pipeline->mainbin;
8195         textbin = player->pipeline->textbin;
8196
8197         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8198         if (current_state < GST_STATE_READY) {
8199                 result = MM_ERROR_PLAYER_INVALID_STATE;
8200                 LOGE("Pipeline is not in proper state");
8201                 goto EXIT;
8202         }
8203
8204         attrs = MMPLAYER_GET_ATTRS(player);
8205         if (!attrs) {
8206                 LOGE("cannot get content attribute");
8207                 result = MM_ERROR_PLAYER_INTERNAL;
8208                 goto EXIT;
8209         }
8210
8211         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8212         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8213                 LOGE("subtitle uri is not proper filepath");
8214                 result = MM_ERROR_PLAYER_INVALID_URI;
8215                 goto EXIT;
8216         }
8217
8218         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8219                 LOGE("failed to get storage info of subtitle path");
8220                 result = MM_ERROR_PLAYER_INVALID_URI;
8221                 goto EXIT;
8222         }
8223
8224         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8225         SECURE_LOGD("new subtitle file path is [%s]", filepath);
8226
8227         if (!strcmp(filepath, subtitle_uri)) {
8228                 LOGD("subtitle path is not changed");
8229                 goto EXIT;
8230         } else {
8231                 if (mm_player_set_attribute((MMHandleType)player, NULL,
8232                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8233                         LOGE("failed to set attribute");
8234                         goto EXIT;
8235                 }
8236         }
8237
8238         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8239         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8240         player->subtitle_language_list = NULL;
8241         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8242
8243         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8244         if (ret != GST_STATE_CHANGE_SUCCESS) {
8245                 LOGE("failed to change state of textbin to READY");
8246                 result = MM_ERROR_PLAYER_INTERNAL;
8247                 goto EXIT;
8248         }
8249
8250         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8251         if (ret != GST_STATE_CHANGE_SUCCESS) {
8252                 LOGE("failed to change state of subparse to READY");
8253                 result = MM_ERROR_PLAYER_INTERNAL;
8254                 goto EXIT;
8255         }
8256
8257         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8258         if (ret != GST_STATE_CHANGE_SUCCESS) {
8259                 LOGE("failed to change state of filesrc to READY");
8260                 result = MM_ERROR_PLAYER_INTERNAL;
8261                 goto EXIT;
8262         }
8263
8264         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8265
8266         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8267
8268         charset = _mmplayer_get_charset(filepath);
8269         if (charset) {
8270                 LOGD("detected charset is %s", charset);
8271                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8272         }
8273
8274         result = _mmplayer_sync_subtitle_pipeline(player);
8275
8276 EXIT:
8277         MMPLAYER_FLEAVE();
8278         return result;
8279 }
8280
8281 /* API to switch between external subtitles */
8282 int
8283 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8284 {
8285         int result = MM_ERROR_NONE;
8286         mmplayer_t *player = (mmplayer_t *)hplayer;
8287         char *path = NULL;
8288
8289         MMPLAYER_FENTER();
8290
8291         /* check player handle */
8292         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8293
8294         /* filepath can be null in idle state */
8295         if (filepath) {
8296                 /* check file path */
8297                 if ((path = strstr(filepath, "file://")))
8298                         result = _mmplayer_exist_file_path(path + 7);
8299                 else
8300                         result = _mmplayer_exist_file_path(filepath);
8301
8302                 if (result != MM_ERROR_NONE) {
8303                         LOGE("invalid subtitle path 0x%X", result);
8304                         return result; /* file not found or permission denied */
8305                 }
8306         }
8307
8308         if (!player->pipeline) {
8309                 /* IDLE state */
8310                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8311                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8312                         LOGE("failed to set attribute");
8313                         return MM_ERROR_PLAYER_INTERNAL;
8314                 }
8315         } else {
8316                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8317                 /* check filepath */
8318                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8319
8320                 if (!__mmplayer_check_subtitle(player)) {
8321                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8322                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8323                                 LOGE("failed to set attribute");
8324                                 return MM_ERROR_PLAYER_INTERNAL;
8325                         }
8326
8327                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8328                                 LOGE("fail to create text pipeline");
8329                                 return MM_ERROR_PLAYER_INTERNAL;
8330                         }
8331
8332                         result = _mmplayer_sync_subtitle_pipeline(player);
8333                 } else {
8334                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8335                 }
8336
8337                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8338                 player->is_external_subtitle_added_now = TRUE;
8339
8340                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8341                 if (!player->subtitle_language_list) {
8342                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8343                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8344                                 LOGW("subtitle language list is not updated yet");
8345                 }
8346                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8347         }
8348
8349         MMPLAYER_FLEAVE();
8350         return result;
8351 }
8352
8353 static int
8354 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8355 {
8356         guint active_idx = 0;
8357         GstStream *stream = NULL;
8358         GList *streams = NULL;
8359         GstEvent *ev = NULL;
8360         GstCaps *caps = NULL;
8361
8362         LOGD("Switching Streams... type: %d, index: %d", type, index);
8363
8364         player->track[type].active_track_index = index;
8365
8366         for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8367                 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8368                 if (player->track[i].total_track_num > 0) {
8369                         active_idx = player->track[i].active_track_index;
8370                         stream = g_ptr_array_index(player->track[i].streams, active_idx);
8371                         streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8372                         LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8373
8374                         if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8375                                 caps = gst_stream_get_caps(stream);
8376                                 if (caps) {
8377                                         _mmplayer_set_audio_attrs(player, caps);
8378                                         gst_caps_unref(caps);
8379                                 }
8380                         }
8381                 }
8382         }
8383
8384         ev = gst_event_new_select_streams(streams);
8385         gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8386         g_list_free(streams);
8387
8388         return MM_ERROR_NONE;
8389 }
8390
8391 static int
8392 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8393 {
8394         int result = MM_ERROR_NONE;
8395         gchar *change_pad_name = NULL;
8396         GstPad *sinkpad = NULL;
8397         mmplayer_gst_element_t *mainbin = NULL;
8398         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8399         GstCaps *caps = NULL;
8400         gint total_track_num = 0;
8401
8402         MMPLAYER_FENTER();
8403
8404         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8405                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8406
8407         LOGD("Change Track(%d) to %d", type, index);
8408
8409         mainbin = player->pipeline->mainbin;
8410
8411         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8412                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8413         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8414                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8415         } else {
8416                 /* Changing Video Track is not supported. */
8417                 LOGE("Track Type Error");
8418                 goto EXIT;
8419         }
8420
8421         if (mainbin[elem_idx].gst == NULL) {
8422                 result = MM_ERROR_PLAYER_NO_OP;
8423                 LOGD("Req track doesn't exist");
8424                 goto EXIT;
8425         }
8426
8427         total_track_num = player->track[type].total_track_num;
8428         if (total_track_num <= 0) {
8429                 result = MM_ERROR_PLAYER_NO_OP;
8430                 LOGD("Language list is not available");
8431                 goto EXIT;
8432         }
8433
8434         if ((index < 0) || (index >= total_track_num)) {
8435                 result = MM_ERROR_INVALID_ARGUMENT;
8436                 LOGD("Not a proper index : %d", index);
8437                 goto EXIT;
8438         }
8439
8440         /*To get the new pad from the selector*/
8441         change_pad_name = g_strdup_printf("sink_%u", index);
8442         if (change_pad_name == NULL) {
8443                 result = MM_ERROR_PLAYER_INTERNAL;
8444                 LOGD("Pad does not exists");
8445                 goto EXIT;
8446         }
8447
8448         LOGD("new active pad name: %s", change_pad_name);
8449
8450         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8451         if (sinkpad == NULL) {
8452                 LOGD("sinkpad is NULL");
8453                 result = MM_ERROR_PLAYER_INTERNAL;
8454                 goto EXIT;
8455         }
8456
8457         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8458         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8459
8460         caps = gst_pad_get_current_caps(sinkpad);
8461         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8462
8463         if (sinkpad)
8464                 gst_object_unref(sinkpad);
8465
8466         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8467                 _mmplayer_set_audio_attrs(player, caps);
8468
8469         if (caps)
8470                 gst_caps_unref(caps);
8471
8472 EXIT:
8473         MMPLAYER_FREEIF(change_pad_name);
8474         return result;
8475 }
8476
8477 int
8478 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8479 {
8480         int result = MM_ERROR_NONE;
8481         mmplayer_t *player = NULL;
8482         mmplayer_gst_element_t *mainbin = NULL;
8483
8484         gint current_active_index = 0;
8485
8486         GstState current_state = GST_STATE_VOID_PENDING;
8487         gint64 time = 0;
8488
8489         MMPLAYER_FENTER();
8490
8491         player = (mmplayer_t *)hplayer;
8492         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8493
8494         if (!player->pipeline) {
8495                 LOGE("Track %d pre setting -> %d", type, index);
8496
8497                 player->track[type].active_track_index = index;
8498                 goto EXIT;
8499         }
8500
8501         mainbin = player->pipeline->mainbin;
8502
8503         current_active_index = player->track[type].active_track_index;
8504
8505         /*If index is same as running index no need to change the pad*/
8506         if (current_active_index == index)
8507                 goto EXIT;
8508
8509         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8510                 result = MM_ERROR_PLAYER_INVALID_STATE;
8511                 goto EXIT;
8512         }
8513
8514         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8515         if (current_state < GST_STATE_PAUSED) {
8516                 result = MM_ERROR_PLAYER_INVALID_STATE;
8517                 LOGW("Pipeline not in porper state");
8518                 goto EXIT;
8519         }
8520
8521         if (MMPLAYER_USE_DECODEBIN(player))
8522                 result = __mmplayer_change_selector_pad(player, type, index);
8523         else
8524                 result = __mmplayer_switch_stream(player, type, index);
8525
8526         if (result != MM_ERROR_NONE) {
8527                 LOGE("failed to change track");
8528                 goto EXIT;
8529         }
8530
8531         player->track[type].active_track_index = index;
8532
8533         if (MMPLAYER_USE_DECODEBIN(player)) {
8534                 GstEvent *event = NULL;
8535                 if (current_state == GST_STATE_PLAYING) {
8536                         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8537                                 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8538                                 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8539                         if (event) {
8540                                 _mmplayer_gst_send_event_to_sink(player, event);
8541                         } else {
8542                                 result = MM_ERROR_PLAYER_INTERNAL;
8543                                 goto EXIT;
8544                         }
8545                 }
8546         }
8547
8548 EXIT:
8549         return result;
8550 }
8551
8552 int
8553 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8554 {
8555         mmplayer_t *player = (mmplayer_t *)hplayer;
8556
8557         MMPLAYER_FENTER();
8558
8559         /* check player handle */
8560         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8561
8562         *silent = player->set_mode.subtitle_off;
8563
8564         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8565
8566         MMPLAYER_FLEAVE();
8567
8568         return MM_ERROR_NONE;
8569 }
8570
8571 static gboolean
8572 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8573 {
8574         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8575         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8576
8577         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8578         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8579
8580         int idx = 0;
8581
8582         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8583                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8584                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8585                         mmplayer_dump_t *dump_s;
8586                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8587                         if (dump_s == NULL) {
8588                                 LOGE("malloc fail");
8589                                 return FALSE;
8590                         }
8591
8592                         dump_s->dump_element_file = NULL;
8593                         dump_s->dump_pad = NULL;
8594                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8595
8596                         if (dump_s->dump_pad) {
8597                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8598                                 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]);
8599                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8600                                 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);
8601                                 /* add list for removed buffer probe and close FILE */
8602                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8603                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8604                                 return TRUE;
8605                         } else {
8606                                 MMPLAYER_FREEIF(dump_s);
8607                                 LOGE("failed to get %s sink pad added", factory_name);
8608                         }
8609                 }
8610         }
8611         return FALSE;
8612 }
8613
8614 static GstPadProbeReturn
8615 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8616 {
8617         FILE *dump_data = (FILE *)u_data;
8618 //      int written = 0;
8619         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8620         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8621
8622         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8623
8624         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8625 #ifdef __DEBUG__
8626         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8627 #endif
8628         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8629
8630         gst_buffer_unmap(buffer, &probe_info);
8631
8632         return GST_PAD_PROBE_OK;
8633 }
8634
8635 static void
8636 __mmplayer_release_dump_list(GList *dump_list)
8637 {
8638         GList *d_list = dump_list;
8639
8640         if (!d_list)
8641                 return;
8642
8643         for (; d_list; d_list = g_list_next(d_list)) {
8644                 mmplayer_dump_t *dump_s = d_list->data;
8645                 if (dump_s->dump_pad) {
8646                         if (dump_s->probe_handle_id)
8647                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8648                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8649                 }
8650                 if (dump_s->dump_element_file) {
8651                         fclose(dump_s->dump_element_file);
8652                         dump_s->dump_element_file = NULL;
8653                 }
8654                 MMPLAYER_FREEIF(dump_s);
8655         }
8656         g_list_free(dump_list);
8657         dump_list = NULL;
8658 }
8659
8660 int
8661 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8662 {
8663         mmplayer_t *player = (mmplayer_t *)hplayer;
8664
8665         MMPLAYER_FENTER();
8666
8667         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8668         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8669
8670         *exist = (bool)player->has_closed_caption;
8671
8672         MMPLAYER_FLEAVE();
8673
8674         return MM_ERROR_NONE;
8675 }
8676
8677 void
8678 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8679 {
8680         MMPLAYER_FENTER();
8681         if (buffer) {
8682 #ifdef __DEBUG__
8683                 LOGD("unref internal gst buffer %p", buffer);
8684 #endif
8685                 gst_buffer_unref((GstBuffer *)buffer);
8686                 buffer = NULL;
8687         }
8688         MMPLAYER_FLEAVE();
8689 }
8690
8691 int
8692 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8693 {
8694         mmplayer_t *player = (mmplayer_t *)hplayer;
8695
8696         MMPLAYER_FENTER();
8697
8698         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8699         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8700
8701         if (MMPLAYER_IS_STREAMING(player))
8702                 *timeout = (int)player->ini.live_state_change_timeout;
8703         else
8704                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8705
8706         LOGD("timeout = %d", *timeout);
8707
8708         MMPLAYER_FLEAVE();
8709         return MM_ERROR_NONE;
8710 }
8711
8712 static void
8713 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8714 {
8715         int i = 0;
8716         MMPLAYER_FENTER();
8717         MMPLAYER_RETURN_IF_FAIL(player);
8718
8719         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8720
8721                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8722                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8723                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8724                         player->storage_info[i].id = -1;
8725                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8726
8727                         if (path_type != MMPLAYER_PATH_MAX)
8728                                 break;
8729                 }
8730         }
8731
8732         MMPLAYER_FLEAVE();
8733 }
8734
8735 int
8736 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8737 {
8738         int ret = MM_ERROR_NONE;
8739         mmplayer_t *player = (mmplayer_t *)hplayer;
8740         MMMessageParamType msg_param = {0, };
8741
8742         MMPLAYER_FENTER();
8743         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8744
8745         LOGW("state changed storage %d:%d", id, state);
8746
8747         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8748                 return MM_ERROR_NONE;
8749
8750         /* FIXME: text path should be handled seperately. */
8751         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8752                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8753                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8754                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8755                 LOGW("external storage is removed");
8756
8757                 if (player->msg_posted == FALSE) {
8758                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8759                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8760                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8761                         player->msg_posted = TRUE;
8762                 }
8763
8764                 /* unrealize the player */
8765                 ret = _mmplayer_unrealize(hplayer);
8766                 if (ret != MM_ERROR_NONE)
8767                         LOGE("failed to unrealize");
8768         }
8769
8770         MMPLAYER_FLEAVE();
8771         return ret;
8772 }
8773
8774 int
8775 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8776 {
8777         int ret = MM_ERROR_NONE;
8778         mmplayer_t *player = (mmplayer_t *)hplayer;
8779         int idx = 0, total = 0;
8780         gchar *result = NULL, *tmp = NULL;
8781
8782         MMPLAYER_FENTER();
8783         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8784         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8785
8786         total = *num = g_list_length(player->adaptive_info.var_list);
8787         if (total <= 0) {
8788                 LOGW("There is no stream variant info.");
8789                 return ret;
8790         }
8791
8792         result = g_strdup("");
8793         for (idx = 0 ; idx < total ; idx++) {
8794                 stream_variant_t *v_data = NULL;
8795                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8796
8797                 if (v_data) {
8798                         gchar data[64] = {0};
8799                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8800
8801                         tmp = g_strconcat(result, data, NULL);
8802                         g_free(result);
8803                         result = tmp;
8804                 } else {
8805                         LOGW("There is no variant data in %d", idx);
8806                         (*num)--;
8807                 }
8808         }
8809
8810         *var_info = (char *)result;
8811
8812         LOGD("variant info %d:%s", *num, *var_info);
8813         MMPLAYER_FLEAVE();
8814         return ret;
8815 }
8816
8817 int
8818 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8819 {
8820         int ret = MM_ERROR_NONE;
8821         mmplayer_t *player = (mmplayer_t *)hplayer;
8822
8823         MMPLAYER_FENTER();
8824         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8825
8826         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8827
8828         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8829         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8830         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8831
8832         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8833                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8834                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8835                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8836
8837                 /* FIXME: seek to current position for applying new variant limitation */
8838         }
8839
8840         MMPLAYER_FLEAVE();
8841         return ret;
8842
8843 }
8844
8845 int
8846 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8847 {
8848         int ret = MM_ERROR_NONE;
8849         mmplayer_t *player = (mmplayer_t *)hplayer;
8850
8851         MMPLAYER_FENTER();
8852         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8853         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8854
8855         *bandwidth = player->adaptive_info.limit.bandwidth;
8856         *width = player->adaptive_info.limit.width;
8857         *height = player->adaptive_info.limit.height;
8858
8859         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8860
8861         MMPLAYER_FLEAVE();
8862         return ret;
8863 }
8864
8865 int
8866 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8867 {
8868         int ret = MM_ERROR_NONE;
8869         mmplayer_t *player = (mmplayer_t *)hplayer;
8870
8871         MMPLAYER_FENTER();
8872         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8873         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8874         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8875
8876         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8877
8878         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8879                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8880         else /* live case */
8881                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8882
8883         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8884
8885         MMPLAYER_FLEAVE();
8886         return ret;
8887 }
8888
8889 int
8890 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8891 {
8892 #define IDX_FIRST_SW_CODEC 0
8893         mmplayer_t *player = (mmplayer_t *)hplayer;
8894         int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8895         const char *attr_name = NULL;
8896         const char *default_type = NULL;
8897         const char *element_hw = NULL;
8898         const char *element_sw = NULL;
8899
8900         MMPLAYER_FENTER();
8901         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8902
8903         LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8904
8905         /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8906         switch (stream_type) {
8907         case MM_PLAYER_STREAM_TYPE_AUDIO:
8908                 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8909                 default_type = player->ini.audiocodec_default_type;
8910                 element_hw = player->ini.audiocodec_element_hw;
8911                 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8912                 break;
8913         case MM_PLAYER_STREAM_TYPE_VIDEO:
8914                 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8915                 default_type = player->ini.videocodec_default_type;
8916                 element_hw = player->ini.videocodec_element_hw;
8917                 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8918                 break;
8919         default:
8920                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8921                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8922                 break;
8923         }
8924
8925         LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8926
8927         if (!strcmp(default_type, "sw"))
8928                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8929         else
8930                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8931
8932         if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8933                 codec_type = default_codec_type;
8934
8935         /* to support codec selection, codec info have to be added in ini file.
8936            in case of hw codec is selected, filter elements should be applied
8937            depending on the hw capabilities. */
8938         if (codec_type != default_codec_type) {
8939                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8940                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8941                         LOGE("There is no codec for type %d", codec_type);
8942                         return MM_ERROR_PLAYER_NO_OP;
8943                 }
8944
8945                 LOGD("sorting is required");
8946                 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8947                         player->need_audio_dec_sorting = TRUE;
8948                 else
8949                         player->need_video_dec_sorting = TRUE;
8950         }
8951
8952         LOGD("update %s codec_type to %d", attr_name, codec_type);
8953         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8954
8955         MMPLAYER_FLEAVE();
8956         return MM_ERROR_NONE;
8957 }
8958
8959 int
8960 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8961 {
8962         mmplayer_t *player = (mmplayer_t *)hplayer;
8963         GstElement *rg_vol_element = NULL;
8964
8965         MMPLAYER_FENTER();
8966
8967         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8968
8969         player->sound.rg_enable = enabled;
8970
8971         /* just hold rgvolume enable value if pipeline is not ready */
8972         if (!player->pipeline || !player->pipeline->audiobin) {
8973                 LOGD("pipeline is not ready. holding rgvolume enable value");
8974                 return MM_ERROR_NONE;
8975         }
8976
8977         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8978
8979         if (!rg_vol_element) {
8980                 LOGD("rgvolume element is not created");
8981                 return MM_ERROR_PLAYER_INTERNAL;
8982         }
8983
8984         if (enabled)
8985                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8986         else
8987                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8988
8989         MMPLAYER_FLEAVE();
8990
8991         return MM_ERROR_NONE;
8992 }
8993
8994 int
8995 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8996 {
8997         mmplayer_t *player = (mmplayer_t *)hplayer;
8998         GstElement *rg_vol_element = NULL;
8999         gboolean enable = FALSE;
9000
9001         MMPLAYER_FENTER();
9002
9003         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9004         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9005
9006         /* just hold enable_rg value if pipeline is not ready */
9007         if (!player->pipeline || !player->pipeline->audiobin) {
9008                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9009                 *enabled = player->sound.rg_enable;
9010                 return MM_ERROR_NONE;
9011         }
9012
9013         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9014
9015         if (!rg_vol_element) {
9016                 LOGD("rgvolume element is not created");
9017                 return MM_ERROR_PLAYER_INTERNAL;
9018         }
9019
9020         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9021         *enabled = (bool)enable;
9022
9023         MMPLAYER_FLEAVE();
9024
9025         return MM_ERROR_NONE;
9026 }
9027
9028 int
9029 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9030 {
9031         mmplayer_t *player = (mmplayer_t *)hplayer;
9032         MMHandleType attrs = 0;
9033         int handle = 0;
9034         int ret = MM_ERROR_NONE;
9035
9036         MMPLAYER_FENTER();
9037
9038         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9039
9040         attrs = MMPLAYER_GET_ATTRS(player);
9041         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9042
9043         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9044         if (!handle) {
9045                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9046                 return MM_ERROR_PLAYER_INTERNAL;
9047         }
9048
9049         player->video_roi.scale_x = scale_x;
9050         player->video_roi.scale_y = scale_y;
9051         player->video_roi.scale_width = scale_width;
9052         player->video_roi.scale_height = scale_height;
9053
9054         /* check video sinkbin is created */
9055         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9056                 return MM_ERROR_NONE;
9057
9058         if (!gst_video_overlay_set_video_roi_area(
9059                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9060                 scale_x, scale_y, scale_width, scale_height))
9061                 ret = MM_ERROR_PLAYER_INTERNAL;
9062         else
9063                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9064                         scale_x, scale_y, scale_width, scale_height);
9065
9066         MMPLAYER_FLEAVE();
9067
9068         return ret;
9069 }
9070
9071 int
9072 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9073 {
9074         mmplayer_t *player = (mmplayer_t *)hplayer;
9075         int ret = MM_ERROR_NONE;
9076
9077         MMPLAYER_FENTER();
9078
9079         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9080         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9081
9082         *scale_x = player->video_roi.scale_x;
9083         *scale_y = player->video_roi.scale_y;
9084         *scale_width = player->video_roi.scale_width;
9085         *scale_height = player->video_roi.scale_height;
9086
9087         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9088                 *scale_x, *scale_y, *scale_width, *scale_height);
9089
9090         return ret;
9091 }
9092
9093 int
9094 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9095 {
9096         mmplayer_t *player = (mmplayer_t *)hplayer;
9097
9098         MMPLAYER_FENTER();
9099
9100         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9101
9102         player->client_pid = pid;
9103
9104         LOGD("client pid[%d] %p", pid, player);
9105
9106         MMPLAYER_FLEAVE();
9107
9108         return MM_ERROR_NONE;
9109 }
9110
9111 int
9112 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9113 {
9114         mmplayer_t *player = (mmplayer_t *)hplayer;
9115         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9116         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9117
9118         MMPLAYER_FENTER();
9119
9120         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9121         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9122
9123         *available = true;
9124         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9125
9126         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9127
9128         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9129                 return MM_ERROR_NONE;
9130
9131         /* in case of audio codec default type is HW */
9132         switch(opt) {
9133                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9134                         if (player->ini.support_audio_effect)
9135                                 return MM_ERROR_NONE;
9136                         elem_id = MMPLAYER_A_FILTER;
9137                 break;
9138                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9139                         if (player->ini.support_replaygain_control)
9140                                 return MM_ERROR_NONE;
9141                         elem_id = MMPLAYER_A_RGVOL;
9142                 break;
9143                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9144                         if (player->ini.support_pitch_control)
9145                                 return MM_ERROR_NONE;
9146                         elem_id = MMPLAYER_A_PITCH;
9147                 break;
9148                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9149                         if (player->ini.support_audio_effect)
9150                                 return MM_ERROR_NONE;
9151                 break;
9152                 /* default case handling is not required */
9153         }
9154
9155         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9156                 LOGW("audio control option [%d] is not available", opt);
9157                 *available = false;
9158         } else {
9159                 /* setting pcm exporting option is allowed before READY state */
9160                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9161                         return MM_ERROR_PLAYER_INVALID_STATE;
9162
9163                 /* check whether the audio filter exist or not after READY state,
9164                    because the sw codec could be added during auto-plugging in some cases */
9165                 if (!player->pipeline ||
9166                         !player->pipeline->audiobin ||
9167                         !player->pipeline->audiobin[elem_id].gst) {
9168                         LOGW("there is no audio elem [%d]", elem_id);
9169                         *available = false;
9170                 }
9171         }
9172
9173         LOGD("audio control opt %d, available %d", opt, *available);
9174
9175         MMPLAYER_FLEAVE();
9176
9177         return MM_ERROR_NONE;
9178 }
9179
9180 static gboolean
9181 __mmplayer_update_duration_value(mmplayer_t *player)
9182 {
9183         gboolean ret = FALSE;
9184         gint64 dur_nsec = 0;
9185         LOGD("try to update duration");
9186
9187         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9188                 player->duration = dur_nsec;
9189                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9190                 ret = TRUE;
9191         }
9192
9193         if (player->duration < 0) {
9194                 LOGW("duration is Non-Initialized !!!");
9195                 player->duration = 0;
9196         }
9197
9198         /* update streaming service type */
9199         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9200
9201         /* check duration is OK */
9202         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9203                 /* FIXIT : find another way to get duration here. */
9204                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9205
9206         return ret;
9207 }
9208
9209 static gboolean
9210 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9211 {
9212         /* update audio params
9213         NOTE : We need original audio params and it can be only obtained from src pad of audio
9214         decoder. Below code only valid when we are not using 'resampler' just before
9215         'audioconverter'. */
9216         GstCaps *caps_a = NULL;
9217         GstPad *pad = NULL;
9218         gint samplerate = 0, channels = 0;
9219         GstStructure *p = NULL;
9220         GstElement *aconv = NULL;
9221
9222         LOGD("try to update audio attrs");
9223
9224         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9225
9226         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9227                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9228         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9229                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9230         } else {
9231                 LOGE("there is no audio converter");
9232                 return FALSE;
9233         }
9234
9235         pad = gst_element_get_static_pad(aconv, "sink");
9236
9237         if (!pad) {
9238                 LOGW("failed to get pad from audio converter");
9239                 return FALSE;
9240         }
9241
9242         caps_a = gst_pad_get_current_caps(pad);
9243         if (!caps_a) {
9244                 LOGW("not ready to get audio caps");
9245                 gst_object_unref(pad);
9246                 return FALSE;
9247         }
9248
9249         p = gst_caps_get_structure(caps_a, 0);
9250
9251         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9252
9253         gst_structure_get_int(p, "rate", &samplerate);
9254         gst_structure_get_int(p, "channels", &channels);
9255
9256         mm_player_set_attribute((MMHandleType)player, NULL,
9257                         "content_audio_samplerate", samplerate,
9258                         "content_audio_channels", channels, NULL);
9259
9260         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9261
9262         gst_caps_unref(caps_a);
9263         gst_object_unref(pad);
9264
9265         return TRUE;
9266 }
9267
9268 static gboolean
9269 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9270 {
9271         LOGD("try to update video attrs");
9272
9273         GstCaps *caps_v = NULL;
9274         GstPad *pad = NULL;
9275         gint tmpNu, tmpDe;
9276         gint width, height;
9277         GstStructure *p = NULL;
9278
9279         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9280         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9281
9282         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9283         if (!pad) {
9284                 LOGD("no videosink sink pad");
9285                 return FALSE;
9286         }
9287
9288         caps_v = gst_pad_get_current_caps(pad);
9289         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9290         if (!caps_v && player->v_stream_caps) {
9291                 caps_v = player->v_stream_caps;
9292                 gst_caps_ref(caps_v);
9293         }
9294
9295         if (!caps_v) {
9296                 LOGD("no negitiated caps from videosink");
9297                 gst_object_unref(pad);
9298                 return FALSE;
9299         }
9300
9301         p = gst_caps_get_structure(caps_v, 0);
9302         gst_structure_get_int(p, "width", &width);
9303         gst_structure_get_int(p, "height", &height);
9304
9305         mm_player_set_attribute((MMHandleType)player, NULL,
9306                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9307
9308         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9309
9310         SECURE_LOGD("width : %d     height : %d", width, height);
9311
9312         gst_caps_unref(caps_v);
9313         gst_object_unref(pad);
9314
9315         if (tmpDe > 0) {
9316                 mm_player_set_attribute((MMHandleType)player, NULL,
9317                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9318                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9319         }
9320
9321         return TRUE;
9322 }
9323
9324 static gboolean
9325 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9326 {
9327         gboolean ret = FALSE;
9328         guint64 data_size = 0;
9329         gchar *path = NULL;
9330         struct stat sb;
9331
9332         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9333         if (!player->duration)
9334                 return FALSE;
9335
9336         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9337                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9338                 if (stat(path, &sb) == 0)
9339                         data_size = (guint64)sb.st_size;
9340
9341         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9342                 data_size = player->http_content_size;
9343         }
9344
9345         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9346
9347         if (data_size) {
9348                 guint64 bitrate = 0;
9349                 guint64 msec_dur = 0;
9350
9351                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9352                 if (msec_dur > 0) {
9353                         bitrate = data_size * 8 * 1000 / msec_dur;
9354                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9355                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9356                         mm_player_set_attribute((MMHandleType)player, NULL,
9357                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9358                         ret = TRUE;
9359                 } else {
9360                         LOGD("player duration is less than 0");
9361                 }
9362         }
9363
9364         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9365                 if (player->total_bitrate) {
9366                         mm_player_set_attribute((MMHandleType)player, NULL,
9367                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9368                         ret = TRUE;
9369                 }
9370         }
9371
9372         return ret;
9373 }
9374
9375 static void
9376 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9377 {
9378         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9379         data->uri_type = uri_type;
9380 }
9381
9382 static int
9383 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9384 {
9385         int ret = MM_ERROR_PLAYER_INVALID_URI;
9386         int mem_size = 0;
9387         char *buffer = NULL;
9388         char *seperator = strchr(path, ',');
9389         char ext[100] = {0,}, size[100] = {0,};
9390
9391         if (seperator) {
9392                 if ((buffer = strstr(path, "ext="))) {
9393                         buffer += strlen("ext=");
9394
9395                         if (strlen(buffer)) {
9396                                 strncpy(ext, buffer, 99);
9397
9398                                 if ((seperator = strchr(ext, ','))
9399                                         || (seperator = strchr(ext, ' '))
9400                                         || (seperator = strchr(ext, '\0'))) {
9401                                         seperator[0] = '\0';
9402                                 }
9403                         }
9404                 }
9405
9406                 if ((buffer = strstr(path, "size="))) {
9407                         buffer += strlen("size=");
9408
9409                         if (strlen(buffer) > 0) {
9410                                 strncpy(size, buffer, 99);
9411
9412                                 if ((seperator = strchr(size, ','))
9413                                         || (seperator = strchr(size, ' '))
9414                                         || (seperator = strchr(size, '\0'))) {
9415                                         seperator[0] = '\0';
9416                                 }
9417
9418                                 mem_size = atoi(size);
9419                         }
9420                 }
9421         }
9422
9423         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9424
9425         if (mem_size && param) {
9426                 if (data->input_mem.buf)
9427                         free(data->input_mem.buf);
9428                 data->input_mem.buf = malloc(mem_size);
9429
9430                 if (data->input_mem.buf) {
9431                         memcpy(data->input_mem.buf, param, mem_size);
9432                         data->input_mem.len = mem_size;
9433                         ret = MM_ERROR_NONE;
9434                 } else {
9435                         LOGE("failed to alloc mem %d", mem_size);
9436                         ret = MM_ERROR_PLAYER_INTERNAL;
9437                 }
9438
9439                 data->input_mem.offset = 0;
9440                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9441         }
9442
9443         return ret;
9444 }
9445
9446 static int
9447 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9448 {
9449         gchar *location = NULL;
9450         GError *err = NULL;
9451         char *path = NULL;
9452         int ret = MM_ERROR_NONE;
9453
9454         if ((path = strstr(uri, "file://"))) {
9455                 location = g_filename_from_uri(uri, NULL, &err);
9456                 if (!location || (err != NULL)) {
9457                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9458                                 (err != NULL) ? err->message : "unknown error");
9459                         if (err)
9460                                 g_error_free(err);
9461
9462                         MMPLAYER_FREEIF(location);
9463
9464                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9465                         return MM_ERROR_PLAYER_INVALID_URI;
9466                 }
9467                 LOGD("path from uri: %s", location);
9468         }
9469
9470         path = (location != NULL) ? (location) : ((char *)uri);
9471
9472
9473         ret = _mmplayer_exist_file_path(path);
9474
9475         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9476         if (ret == MM_ERROR_NONE) {
9477                 if (_mmplayer_is_sdp_file(path)) {
9478                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9479                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9480                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9481                 } else {
9482                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9483                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9484                 }
9485         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9486                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9487         } else {
9488                 LOGE("invalid uri, could not play..");
9489                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9490         }
9491
9492         MMPLAYER_FREEIF(location);
9493
9494         return ret;
9495 }
9496
9497 static mmplayer_video_decoded_data_info_t *
9498 __mmplayer_create_stream_from_pad(GstPad *pad)
9499 {
9500         GstCaps *caps = NULL;
9501         GstStructure *structure = NULL;
9502         unsigned int fourcc = 0;
9503         const gchar *string_format = NULL;
9504         mmplayer_video_decoded_data_info_t *stream = NULL;
9505         gint width, height;
9506         MMPixelFormatType format;
9507         GstVideoInfo info;
9508
9509         caps = gst_pad_get_current_caps(pad);
9510         if (!caps) {
9511                 LOGE("Caps is NULL.");
9512                 return NULL;
9513         }
9514
9515 #ifdef __DEBUG__
9516         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9517 #endif
9518         structure = gst_caps_get_structure(caps, 0);
9519         gst_structure_get_int(structure, "width", &width);
9520         gst_structure_get_int(structure, "height", &height);
9521         string_format = gst_structure_get_string(structure, "format");
9522
9523         if (string_format)
9524                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9525         format = _mmplayer_get_pixtype(fourcc);
9526         gst_video_info_from_caps(&info, caps);
9527         gst_caps_unref(caps);
9528
9529         /* moved here */
9530         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9531                 LOGE("Wrong condition!!");
9532                 return NULL;
9533         }
9534
9535         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9536         if (!stream) {
9537                 LOGE("failed to alloc mem for video data");
9538                 return NULL;
9539         }
9540
9541         stream->width = width;
9542         stream->height = height;
9543         stream->format = format;
9544         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9545
9546         return stream;
9547 }
9548
9549 static void
9550 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9551 {
9552         unsigned int pitch = 0;
9553         unsigned int size = 0;
9554         int index = 0;
9555         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9556         tbm_bo bo = NULL;
9557
9558         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9559                 bo = gst_tizen_memory_get_bos(mem, index);
9560                 if (bo)
9561                         stream->bo[index] = tbm_bo_ref(bo);
9562                 else
9563                         LOGE("failed to get bo for index %d", index);
9564         }
9565
9566         for (index = 0; index < stream->plane_num; index++) {
9567                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9568                 stream->stride[index] = pitch;
9569                 if (pitch)
9570                         stream->elevation[index] = size / pitch;
9571                 else
9572                         stream->elevation[index] = stream->height;
9573         }
9574 }
9575
9576 static gboolean
9577 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9578 {
9579         if (stream->format == MM_PIXEL_FORMAT_I420) {
9580                 int ret = TBM_SURFACE_ERROR_NONE;
9581                 tbm_surface_h surface;
9582                 tbm_surface_info_s info;
9583
9584                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9585
9586                 ret = tbm_surface_get_info(surface, &info);
9587                 if (ret != TBM_SURFACE_ERROR_NONE) {
9588                         tbm_surface_destroy(surface);
9589                         return FALSE;
9590                 }
9591
9592                 tbm_surface_destroy(surface);
9593                 stream->stride[0] = info.planes[0].stride;
9594                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9595                 stream->stride[1] = info.planes[1].stride;
9596                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9597                 stream->stride[2] = info.planes[2].stride;
9598                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9599                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9600         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9601                 stream->stride[0] = stream->width * 4;
9602                 stream->elevation[0] = stream->height;
9603                 stream->bo_size = stream->stride[0] * stream->height;
9604         } else {
9605                 LOGE("Not support format %d", stream->format);
9606                 return FALSE;
9607         }
9608
9609         return TRUE;
9610 }
9611
9612 static gboolean
9613 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9614 {
9615         tbm_bo_handle thandle;
9616         gboolean is_mapped;
9617         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9618         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9619         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9620         int i = 0;
9621         int j = 0;
9622         int k = 0;
9623         unsigned char *src = NULL;
9624         unsigned char *dest = NULL;
9625         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9626
9627         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9628         if (!is_mapped) {
9629                 LOGE("fail to gst_memory_map");
9630                 return FALSE;
9631         }
9632
9633         if (!mapinfo.data) {
9634                 LOGE("data pointer is wrong");
9635                 goto ERROR;
9636         }
9637
9638         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9639         if (!stream->bo[0]) {
9640                 LOGE("Fail to tbm_bo_alloc!!");
9641                 goto ERROR;
9642         }
9643
9644         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9645         if (!thandle.ptr) {
9646                 LOGE("thandle pointer is wrong");
9647                 goto ERROR;
9648         }
9649
9650         if (stream->format == MM_PIXEL_FORMAT_I420) {
9651                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9652                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9653                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9654                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9655
9656                 dest_offset[0] = 0;
9657                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9658                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9659
9660                 for (i = 0; i < 3; i++) {
9661                         src = mapinfo.data + src_offset[i];
9662                         dest = thandle.ptr + dest_offset[i];
9663
9664                         if (i > 0)
9665                                 k = 1;
9666
9667                         for (j = 0; j < stream->height >> k; j++) {
9668                                 memcpy(dest, src, stream->width>>k);
9669                                 src += src_stride[i];
9670                                 dest += stream->stride[i];
9671                         }
9672                 }
9673         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9674                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9675         } else {
9676                 LOGE("Not support format %d", stream->format);
9677                 goto ERROR;
9678         }
9679
9680         tbm_bo_unmap(stream->bo[0]);
9681         gst_memory_unmap(mem, &mapinfo);
9682
9683         return TRUE;
9684
9685 ERROR:
9686         if (stream->bo[0])
9687                 tbm_bo_unmap(stream->bo[0]);
9688
9689         if (is_mapped)
9690                 gst_memory_unmap(mem, &mapinfo);
9691
9692         return FALSE;
9693 }
9694
9695 static void
9696 __mmplayer_set_pause_state(mmplayer_t *player)
9697 {
9698         if (player->sent_bos)
9699                 return;
9700
9701         /* rtsp case, get content attrs by GstMessage */
9702         if (MMPLAYER_IS_RTSP_STREAMING(player))
9703                 return;
9704
9705         /* it's first time to update all content attrs. */
9706         _mmplayer_update_content_attrs(player, ATTR_ALL);
9707 }
9708
9709 static void
9710 __mmplayer_set_playing_state(mmplayer_t *player)
9711 {
9712         gchar *audio_codec = NULL;
9713
9714         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9715                 /* initialize because auto resume is done well. */
9716                 player->resumed_by_rewind = FALSE;
9717                 player->playback_rate = 1.0;
9718         }
9719
9720         if (player->sent_bos)
9721                 return;
9722
9723         /* try to get content metadata */
9724
9725         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9726          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9727          * legacy mmfw-player api
9728          */
9729         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9730
9731         if ((player->cmd == MMPLAYER_COMMAND_START)
9732                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9733                 __mmplayer_handle_missed_plugin(player);
9734         }
9735
9736         /* check audio codec field is set or not
9737          * we can get it from typefinder or codec's caps.
9738          */
9739         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9740
9741         /* The codec format can't be sent for audio only case like amr, mid etc.
9742          * Because, parser don't make related TAG.
9743          * So, if it's not set yet, fill it with found data.
9744          */
9745         if (!audio_codec) {
9746                 if (g_strrstr(player->type, "audio/midi"))
9747                         audio_codec = "MIDI";
9748                 else if (g_strrstr(player->type, "audio/x-amr"))
9749                         audio_codec = "AMR";
9750                 else if (g_strrstr(player->type, "audio/mpeg")
9751                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9752                         audio_codec = "AAC";
9753                 else
9754                         audio_codec = "unknown";
9755
9756                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9757                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9758                         LOGE("failed to set attribute");
9759
9760                 LOGD("set audio codec type with caps");
9761         }
9762
9763         return;
9764 }