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