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