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