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