[1.0.2] fix wrong condition
[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 #define MQ_UNLINKED_CACHE_TIME         (500 * GST_MSECOND)
111
112 /*---------------------------------------------------------------------------
113 |    LOCAL CONSTANT DEFINITIONS:                                                                                        |
114 ---------------------------------------------------------------------------*/
115
116 /*---------------------------------------------------------------------------
117 |    LOCAL DATA TYPE DEFINITIONS:                                                                                       |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120  We are defining our own and will be removed when it actually exposed */
121 typedef enum {
122         GST_AUTOPLUG_SELECT_TRY,
123         GST_AUTOPLUG_SELECT_EXPOSE,
124         GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
126
127 /*---------------------------------------------------------------------------
128 |    GLOBAL VARIABLE DEFINITIONS:                                                                                       |
129 ---------------------------------------------------------------------------*/
130
131 /*---------------------------------------------------------------------------
132 |    LOCAL VARIABLE DEFINITIONS:                                                                                        |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
135
136 /*---------------------------------------------------------------------------
137 |    LOCAL FUNCTION PROTOTYPES:                                                                                         |
138 ---------------------------------------------------------------------------*/
139 static int              __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int              __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int              __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int              __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int              __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int              __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void             __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
146 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
147 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
148 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
149
150 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static void             __mmplayer_release_misc(mmplayer_t *player);
152 static void             __mmplayer_release_misc_post(mmplayer_t *player);
153 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
154 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
157 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
158
159 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
160 static int              __mmplayer_handle_missed_plugin(mmplayer_t *player);
161 static void             __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
162 static void             __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
163 static void             __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
164 static gpointer __mmplayer_gapless_play_thread(gpointer data);
165 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
166 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_release_dump_list(GList *dump_list);
168 static int              __mmplayer_gst_realize(mmplayer_t *player);
169 static int              __mmplayer_gst_unrealize(mmplayer_t *player);
170 static int              __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
171 static int              __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
172
173 /* util */
174 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
175 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
176 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
177 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
178 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
179 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
180 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
181 static void             __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
182 static void             __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
183 static void             __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
184 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
185 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
187 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188
189 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
190 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
191 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192
193 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
194 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
195 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
196 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197
198 static void __mmplayer_set_pause_state(mmplayer_t *player);
199 static void __mmplayer_set_playing_state(mmplayer_t *player);
200 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
201 /*===========================================================================================
202 |                                                                                                                                                                                       |
203 |  FUNCTION DEFINITIONS                                                                                                                                         |
204 |                                                                                                                                                                                       |
205 ========================================================================================== */
206
207 /* This function should be called after the pipeline goes PAUSED or higher
208 state. */
209 gboolean
210 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
211 {
212         static gboolean has_duration = FALSE;
213         static gboolean has_video_attrs = FALSE;
214         static gboolean has_audio_attrs = FALSE;
215         static gboolean has_bitrate = FALSE;
216         gboolean missing_only = FALSE;
217         gboolean all = FALSE;
218         MMHandleType attrs = 0;
219
220         MMPLAYER_FENTER();
221
222         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
223
224         /* check player state here */
225         if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
226                 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
227                 /* give warning now only */
228                 LOGW("be careful. content attributes may not available in this state ");
229         }
230
231         /* get content attribute first */
232         attrs = MMPLAYER_GET_ATTRS(player);
233         if (!attrs) {
234                 LOGE("cannot get content attribute");
235                 return FALSE;
236         }
237
238         /* get update flag */
239
240         if (flag & ATTR_MISSING_ONLY) {
241                 missing_only = TRUE;
242                 LOGD("updating missed attr only");
243         }
244
245         if (flag & ATTR_ALL) {
246                 all = TRUE;
247                 has_duration = FALSE;
248                 has_video_attrs = FALSE;
249                 has_audio_attrs = FALSE;
250                 has_bitrate = FALSE;
251
252                 LOGD("updating all attrs");
253         }
254
255         if (missing_only && all) {
256                 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
257                 missing_only = FALSE;
258         }
259
260         if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
261                 has_duration = __mmplayer_update_duration_value(player);
262
263         if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
264                 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
265
266         if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
267                 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
268
269         if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
270                 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
271
272         MMPLAYER_FLEAVE();
273
274         return TRUE;
275 }
276
277 MMStreamingType
278 _mmplayer_get_stream_service_type(mmplayer_t *player)
279 {
280         MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
281
282         MMPLAYER_FENTER();
283
284         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
285                         player->pipeline &&
286                         player->pipeline->mainbin &&
287                         player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
288                         STREAMING_SERVICE_NONE);
289
290         /* streaming service type if streaming */
291         if (!MMPLAYER_IS_STREAMING(player))
292                 return STREAMING_SERVICE_NONE;
293
294         streaming_type = (player->duration == 0) ?
295                 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
296
297         switch (streaming_type) {
298         case STREAMING_SERVICE_LIVE:
299                 LOGD("it's live streaming");
300                 break;
301         case STREAMING_SERVICE_VOD:
302                 LOGD("it's vod streaming");
303                 break;
304         default:
305                 LOGE("should not get here");
306                 break;
307         }
308
309         MMPLAYER_FLEAVE();
310
311         return streaming_type;
312 }
313
314 /* this function sets the player state and also report
315  * it to application by calling callback function
316  */
317 void
318 _mmplayer_set_state(mmplayer_t *player, int state)
319 {
320         MMMessageParamType msg = {0, };
321
322         MMPLAYER_RETURN_IF_FAIL(player);
323
324         if (MMPLAYER_CURRENT_STATE(player) == state) {
325                 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
326                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
327                 return;
328         }
329
330         /* update player states */
331         MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
332         MMPLAYER_CURRENT_STATE(player) = state;
333
334         if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
335                 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336
337         /* print state */
338         MMPLAYER_PRINT_STATE(player);
339
340         switch (MMPLAYER_CURRENT_STATE(player)) {
341         case MM_PLAYER_STATE_NULL:
342         case MM_PLAYER_STATE_READY:
343                 break;
344         case MM_PLAYER_STATE_PAUSED:
345                 __mmplayer_set_pause_state(player);
346                 break;
347         case MM_PLAYER_STATE_PLAYING:
348                 __mmplayer_set_playing_state(player);
349                 break;
350         case MM_PLAYER_STATE_NONE:
351         default:
352                 LOGW("invalid target state, there is nothing to do.");
353                 break;
354         }
355
356
357         /* post message to application */
358         if (MMPLAYER_TARGET_STATE(player) == state) {
359                 /* fill the message with state of player */
360                 msg.union_type = MM_MSG_UNION_STATE;
361                 msg.state.previous = MMPLAYER_PREV_STATE(player);
362                 msg.state.current = MMPLAYER_CURRENT_STATE(player);
363
364                 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
365
366                 /* state changed by resource callback */
367                 if (player->interrupted_by_resource)
368                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
369                 else /* state changed by usecase */
370                         MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371
372         } else {
373                 LOGD("intermediate state, do nothing.");
374                 MMPLAYER_PRINT_STATE(player);
375                 return;
376         }
377
378         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
379                 && !player->sent_bos) {
380                 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
381                 player->sent_bos = TRUE;
382         }
383
384         return;
385 }
386
387 int
388 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
389 {
390         mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
391         mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
392
393         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
394 #ifdef __DEBUG__
395         LOGD("incoming command : %d ", command);
396 #endif
397         current_state = MMPLAYER_CURRENT_STATE(player);
398         pending_state = MMPLAYER_PENDING_STATE(player);
399
400         MMPLAYER_PRINT_STATE(player);
401
402         switch (command) {
403         case MMPLAYER_COMMAND_CREATE:
404         {
405                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
406
407                 if (current_state == MM_PLAYER_STATE_NULL ||
408                         current_state == MM_PLAYER_STATE_READY ||
409                         current_state == MM_PLAYER_STATE_PAUSED ||
410                         current_state == MM_PLAYER_STATE_PLAYING)
411                         goto NO_OP;
412         }
413         break;
414
415         case MMPLAYER_COMMAND_DESTROY:
416         {
417                 /* destroy can called anytime */
418
419                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
420         }
421         break;
422
423         case MMPLAYER_COMMAND_REALIZE:
424         {
425                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
426
427                 if (pending_state != MM_PLAYER_STATE_NONE) {
428                         goto INVALID_STATE;
429                 } else {
430                         /* need ready state to realize */
431                         if (current_state == MM_PLAYER_STATE_READY)
432                                 goto NO_OP;
433
434                         if (current_state != MM_PLAYER_STATE_NULL)
435                                 goto INVALID_STATE;
436                 }
437         }
438         break;
439
440         case MMPLAYER_COMMAND_UNREALIZE:
441         {
442                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
443
444                 if (current_state == MM_PLAYER_STATE_NULL)
445                         goto NO_OP;
446         }
447         break;
448
449         case MMPLAYER_COMMAND_START:
450         {
451                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
452
453                 if (pending_state == MM_PLAYER_STATE_NONE) {
454                         if (current_state == MM_PLAYER_STATE_PLAYING)
455                                 goto NO_OP;
456                         else if (current_state  != MM_PLAYER_STATE_READY &&
457                                 current_state != MM_PLAYER_STATE_PAUSED)
458                                 goto INVALID_STATE;
459                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
460                         goto ALREADY_GOING;
461                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
462                         LOGD("player is going to paused state, just change the pending state as playing");
463                 } else {
464                         goto INVALID_STATE;
465                 }
466         }
467         break;
468
469         case MMPLAYER_COMMAND_STOP:
470         {
471                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472
473                 if (current_state == MM_PLAYER_STATE_READY)
474                         goto NO_OP;
475
476                 /* need playing/paused state to stop */
477                 if (current_state != MM_PLAYER_STATE_PLAYING &&
478                          current_state != MM_PLAYER_STATE_PAUSED)
479                         goto INVALID_STATE;
480         }
481         break;
482
483         case MMPLAYER_COMMAND_PAUSE:
484         {
485                 if (MMPLAYER_IS_LIVE_STREAMING(player))
486                         goto NO_OP;
487
488                 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
489                         goto NOT_COMPLETED_SEEK;
490
491                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
492
493                 if (pending_state == MM_PLAYER_STATE_NONE) {
494                         if (current_state == MM_PLAYER_STATE_PAUSED)
495                                 goto NO_OP;
496                         else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
497                                 goto INVALID_STATE;
498                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499                         goto ALREADY_GOING;
500                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
501                         if (current_state == MM_PLAYER_STATE_PAUSED)
502                                 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
503                         else
504                                 goto INVALID_STATE;
505                 }
506         }
507         break;
508
509         case MMPLAYER_COMMAND_RESUME:
510         {
511                 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
512                         goto NOT_COMPLETED_SEEK;
513
514                 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
515
516                 if (pending_state == MM_PLAYER_STATE_NONE) {
517                         if (current_state == MM_PLAYER_STATE_PLAYING)
518                                 goto NO_OP;
519                         else if (current_state != MM_PLAYER_STATE_PAUSED)
520                                 goto INVALID_STATE;
521                 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
522                         goto ALREADY_GOING;
523                 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
524                         LOGD("player is going to paused state, just change the pending state as playing");
525                 } else {
526                         goto INVALID_STATE;
527                 }
528         }
529                 break;
530
531         default:
532                 break;
533         }
534         player->cmd = command;
535
536         return MM_ERROR_NONE;
537
538 INVALID_STATE:
539         LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
540                 MMPLAYER_STATE_GET_NAME(current_state), command);
541         return MM_ERROR_PLAYER_INVALID_STATE;
542
543 NOT_COMPLETED_SEEK:
544         LOGW("not completed seek");
545         return MM_ERROR_PLAYER_DOING_SEEK;
546
547 NO_OP:
548         LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
549         return MM_ERROR_PLAYER_NO_OP;
550
551 ALREADY_GOING:
552         LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
553         return MM_ERROR_PLAYER_NO_OP;
554 }
555
556 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
557 {
558         int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
559         mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560
561         switch (type) {
562                 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
563                         rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
564                         break;
565                 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
566                         rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
567                         break;
568                 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
569                         rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570                         break;
571                 default:
572                         LOGE("invalid mmplayer resource type %d", type);
573                         return MM_ERROR_PLAYER_INTERNAL;
574         }
575
576         if (player->hw_resource[type] != NULL) {
577                 LOGD("[%d type] resource was already acquired", type);
578                 return MM_ERROR_NONE;
579         }
580
581         LOGD("mark for acquire [%d type] resource", type);
582         rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
583                         rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
584         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
585                 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
586                 return MM_ERROR_PLAYER_INTERNAL;
587         }
588
589         LOGD("commit [%d type] resource", type);
590         rm_ret = mm_resource_manager_commit(player->resource_manager);
591         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
592                 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
593                 return MM_ERROR_PLAYER_INTERNAL;
594         }
595
596         MMPLAYER_FLEAVE();
597         return MM_ERROR_NONE;
598 }
599
600 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
601 {
602         int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603
604         MMPLAYER_RETURN_IF_FAIL(player);
605         MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
606
607         rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
608         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
609                 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
610                 goto rm_destroy;
611         }
612
613         rm_ret = mm_resource_manager_commit(player->resource_manager);
614         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
615                 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
616
617 rm_destroy:
618         /* de-initialize resource manager */
619         rm_ret = mm_resource_manager_destroy(player->resource_manager);
620         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
621                 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
622                 return;
623         }
624
625         player->resource_manager = NULL;
626
627         LOGD("resource manager is destroyed");
628 }
629
630 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
631 {
632         int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
633
634         MMPLAYER_FENTER();
635
636         if (player->hw_resource[type] == NULL) {
637                 LOGD("there is no acquired [%d type] resource", type);
638                 return MM_ERROR_NONE;
639         }
640
641         LOGD("mark for release [%d type] resource", type);
642         rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
643         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
644                 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
645                 return MM_ERROR_PLAYER_INTERNAL;
646         }
647
648         player->hw_resource[type] = NULL;
649
650         LOGD("commit [%d type] resource", type);
651         rm_ret = mm_resource_manager_commit(player->resource_manager);
652         if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
653                 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
654                 return MM_ERROR_PLAYER_INTERNAL;
655         }
656
657         MMPLAYER_FLEAVE();
658         return MM_ERROR_NONE;
659 }
660
661 static void
662 __mmplayer_initialize_gapless_play(mmplayer_t *player)
663 {
664         int i;
665
666         MMPLAYER_FENTER();
667
668         player->smooth_streaming = FALSE;
669         player->videodec_linked = 0;
670         player->audiodec_linked = 0;
671         player->textsink_linked = 0;
672         player->is_external_subtitle_present = FALSE;
673         player->is_external_subtitle_added_now = FALSE;
674         player->not_supported_codec = MISSING_PLUGIN_NONE;
675         player->can_support_codec = FOUND_PLUGIN_NONE;
676         player->pending_seek.is_pending = false;
677         player->pending_seek.pos = 0;
678         player->msg_posted = FALSE;
679         player->has_many_types = FALSE;
680         player->no_more_pad = FALSE;
681         player->not_found_demuxer = 0;
682         player->seek_state = MMPLAYER_SEEK_NONE;
683         player->is_subtitle_force_drop = FALSE;
684         player->play_subtitle = FALSE;
685         player->adjust_subtitle_pos = 0;
686
687         player->total_bitrate = 0;
688         player->total_maximum_bitrate = 0;
689
690         _mmplayer_track_initialize(player);
691         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
692
693         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
694                 player->bitrate[i] = 0;
695                 player->maximum_bitrate[i] = 0;
696         }
697
698         if (player->v_stream_caps) {
699                 gst_caps_unref(player->v_stream_caps);
700                 player->v_stream_caps = NULL;
701         }
702
703         mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
704
705         /* clean found audio decoders */
706         if (player->audio_decoders) {
707                 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
708                 player->audio_decoders = NULL;
709         }
710
711         __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
712
713         MMPLAYER_FLEAVE();
714 }
715
716 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
717 {
718         LOGI("set pipeline reconfigure state %d", state);
719         MMPLAYER_RECONFIGURE_LOCK(player);
720         player->gapless.reconfigure = state;
721         if (!state) /* wake up the waiting job */
722                 MMPLAYER_RECONFIGURE_SIGNAL(player);
723         MMPLAYER_RECONFIGURE_UNLOCK(player);
724 }
725
726 static gpointer
727 __mmplayer_gapless_play_thread(gpointer data)
728 {
729         mmplayer_t *player = (mmplayer_t *)data;
730         mmplayer_gst_element_t *mainbin = NULL;
731
732         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
733
734         MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
735         while (!player->gapless_play_thread_exit) {
736                 LOGD("gapless play thread started. waiting for signal.");
737                 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
738
739                 LOGD("reconfigure pipeline for gapless play.");
740
741                 if (player->gapless_play_thread_exit) {
742                         _mmplayer_set_reconfigure_state(player, FALSE);
743                         LOGD("exiting gapless play thread");
744                         break;
745                 }
746
747                 mainbin = player->pipeline->mainbin;
748
749                 if (MMPLAYER_USE_DECODEBIN(player)) {
750                         MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
751                         MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* decodebin */
752                         MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
753                         MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
754                 } else {
755                         MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* uridecodebin */
756                         mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
757                         mainbin[MMPLAYER_M_SRC].gst = NULL;
758                 }
759
760                 /* Initialize Player values */
761                 __mmplayer_initialize_gapless_play(player);
762
763                 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
764         }
765         MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
766
767         return NULL;
768 }
769
770 static void
771 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
772 {
773         GSource *source = NULL;
774
775         MMPLAYER_FENTER();
776
777         source = g_main_context_find_source_by_id(context, source_id);
778         if (source != NULL) {
779                 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
780                 g_source_destroy(source);
781         }
782
783         MMPLAYER_FLEAVE();
784 }
785
786 void
787 _mmplayer_watcher_removed_notify(gpointer data)
788 {
789         mmplayer_t *player = (mmplayer_t *)data;
790         MMPLAYER_RETURN_IF_FAIL(player);
791
792         MMPLAYER_BUS_WATCHER_LOCK(player);
793         player->bus_watcher = 0;
794         MMPLAYER_BUS_WATCHER_SIGNAL(player);
795         MMPLAYER_BUS_WATCHER_UNLOCK(player);
796 }
797
798 void
799 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
800 {
801         mmplayer_t *player = (mmplayer_t *)hplayer;
802         gint64 end_time = 0;
803         MMPLAYER_FENTER();
804         MMPLAYER_RETURN_IF_FAIL(player);
805
806         /* disconnecting bus watch */
807         if (player->bus_watcher > 0) {
808                 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
809                 MMPLAYER_BUS_WATCHER_LOCK(player);
810                 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
811                 while (player->bus_watcher > 0) {
812                         if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
813                                 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
814                                                 player->bus_watcher);
815                                 break;
816                         }
817                 }
818                 MMPLAYER_BUS_WATCHER_UNLOCK(player);
819                 g_mutex_clear(&player->bus_watcher_mutex);
820                 g_cond_clear(&player->bus_watcher_cond);
821         }
822
823         MMPLAYER_FLEAVE();
824 }
825
826 void
827 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
828 {
829         mmplayer_t *player = (mmplayer_t *)hplayer;
830         GstMessage *msg = NULL;
831         GQueue *queue = NULL;
832
833         MMPLAYER_FENTER();
834         MMPLAYER_RETURN_IF_FAIL(player);
835
836         /* destroy the gst bus msg thread */
837         if (player->bus_msg_thread) {
838                 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
839                 player->bus_msg_thread_exit = TRUE;
840                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
841                 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
842
843                 LOGD("gst bus msg thread exit.");
844                 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
845                 player->bus_msg_thread = NULL;
846
847                 g_mutex_clear(&player->bus_msg_thread_mutex);
848                 g_cond_clear(&player->bus_msg_thread_cond);
849         }
850
851         g_mutex_lock(&player->bus_msg_q_lock);
852         queue = player->bus_msg_q;
853         while (!g_queue_is_empty(queue)) {
854                 msg = (GstMessage *)g_queue_pop_head(queue);
855                 if (!msg) {
856                         LOGW("msg is null");
857                         continue;
858                 }
859                 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
860                 gst_message_unref(msg);
861         }
862         g_mutex_unlock(&player->bus_msg_q_lock);
863
864         MMPLAYER_FLEAVE();
865 }
866
867 gboolean
868 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
869 {
870         GstElement *parent = NULL;
871
872         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
873         MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
874
875         /* lock */
876         MMPLAYER_FSINK_LOCK(player);
877
878         /* get parent of fakesink */
879         parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
880         if (!parent) {
881                 LOGD("fakesink already removed");
882                 goto ERROR;
883         }
884
885         gst_element_set_locked_state(fakesink->gst, TRUE);
886
887         /* setting the state to NULL never returns async
888          * so no need to wait for completion of state transition
889          */
890         if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
891                 LOGE("fakesink state change failure!");
892                 /* FIXIT : should I return here? or try to proceed to next? */
893                 /* return FALSE; */
894
895         /* remove fakesink from it's parent */
896         if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
897                 LOGE("failed to remove fakesink");
898
899                 gst_object_unref(parent);
900
901                 goto ERROR;
902         }
903
904         gst_object_unref(parent);
905
906         LOGD("state-holder removed");
907
908         gst_element_set_locked_state(fakesink->gst, FALSE);
909
910         MMPLAYER_FSINK_UNLOCK(player);
911         return TRUE;
912
913 ERROR:
914         if (fakesink->gst)
915                 gst_element_set_locked_state(fakesink->gst, FALSE);
916
917         MMPLAYER_FSINK_UNLOCK(player);
918         return FALSE;
919 }
920
921 static GstPadProbeReturn
922 __mmplayer_gst_combiner_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
923 {
924         LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
925         return GST_PAD_PROBE_OK;
926 }
927
928 static void
929 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
930 {
931         gint64 stop_running_time = 0;
932         gint64 position_running_time = 0;
933         gint64 position = 0;
934         gint idx = 0;
935
936         for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
937                 if ((player->gapless.update_segment[idx] == TRUE) ||
938                         !(player->track[idx].event_probe_id)) {
939 #ifdef __DEBUG__
940                         LOGW("[%d] skip", idx);
941 #endif
942                         continue;
943                 }
944
945                 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
946                         stop_running_time =
947                                 gst_segment_to_running_time(&player->gapless.segment[idx],
948                                                 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
949                 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
950                         stop_running_time =
951                                 gst_segment_to_running_time(&player->gapless.segment[idx],
952                                                 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
953                 } else {
954                         LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
955                         stop_running_time =
956                                 gst_segment_to_running_time(&player->gapless.segment[idx],
957                                                 GST_FORMAT_TIME, player->duration);
958                 }
959
960                 position_running_time =
961                         gst_segment_to_running_time(&player->gapless.segment[idx],
962                         GST_FORMAT_TIME, player->gapless.segment[idx].position);
963
964                 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
965                         GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
966                         idx,
967                         GST_TIME_ARGS(stop_running_time),
968                         GST_TIME_ARGS(position_running_time),
969                         GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
970                         GST_FORMAT_TIME, player->gapless.segment[idx].start)));
971
972                 position_running_time = MAX(position_running_time, stop_running_time);
973                 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
974                                                                                 GST_FORMAT_TIME, player->gapless.segment[idx].start);
975                 position_running_time = MAX(0, position_running_time);
976                 position = MAX(position, position_running_time);
977         }
978
979         if (position != 0) {
980                 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
981                         stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
982                         GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
983
984                 player->gapless.start_time[stream_type] += position;
985         }
986
987         return;
988 }
989
990 static GstPadProbeReturn
991 __mmplayer_gst_combiner_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
992 {
993         GstPadProbeReturn ret = GST_PAD_PROBE_OK;
994         GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
995         mmplayer_t *player = (mmplayer_t *)data;
996         GstCaps *caps = NULL;
997         GstStructure *str = NULL;
998         const gchar *name = NULL;
999         mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1000         gboolean caps_ret = TRUE;
1001
1002         if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1003                 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1004                 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1005                 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1006                 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1007                 return ret;
1008
1009         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1010         if (!caps_ret) {
1011                 GstStream *stream = NULL;
1012
1013                 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START)
1014                         goto ERROR;
1015
1016                 gst_event_parse_stream (event, &stream);
1017                 if (stream == NULL) {
1018                         LOGW ("Got a STREAM_START event without a GstStream");
1019                         goto ERROR;
1020                 }
1021
1022                 name = gst_stream_type_get_name(gst_stream_get_stream_type(stream));
1023                 gst_object_unref (stream);
1024         }
1025
1026         if (!name)
1027                 goto ERROR;
1028
1029         if (strstr(name, "audio")) {
1030                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1031         } else if (strstr(name, "video")) {
1032                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1033         } else {
1034                 /* text track is not supportable */
1035                 LOGE("invalid name %s", name);
1036                 goto ERROR;
1037         }
1038
1039         switch (GST_EVENT_TYPE(event)) {
1040         case GST_EVENT_EOS:
1041                 {
1042                         /* in case of gapless, drop eos event not to send it to sink */
1043                         MMPLAYER_RECONFIGURE_LOCK(player);
1044                         if (player->gapless.reconfigure && !player->msg_posted) {
1045                                 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1046                                 ret = GST_PAD_PROBE_DROP;
1047                         }
1048                         MMPLAYER_RECONFIGURE_UNLOCK(player);
1049                         break;
1050                 }
1051         case GST_EVENT_STREAM_START:
1052                 {
1053                         __mmplayer_gst_selector_update_start_time(player, stream_type);
1054                         break;
1055                 }
1056         case GST_EVENT_FLUSH_STOP:
1057                 {
1058                         LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1059                         gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1060                         player->gapless.start_time[stream_type] = 0;
1061                         break;
1062                 }
1063         case GST_EVENT_SEGMENT:
1064                 {
1065                         GstSegment segment;
1066                         GstEvent *tmpev;
1067
1068                         LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1069                         gst_event_copy_segment(event, &segment);
1070
1071                         if (segment.format != GST_FORMAT_TIME)
1072                                 break;
1073
1074                         LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1075                                  ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1076                                  ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1077                                 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1078                                 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1079                                 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1080
1081                         /* keep the all the segment ev to cover the seeking */
1082                         gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1083                         player->gapless.update_segment[stream_type] = TRUE;
1084
1085                         if (!player->gapless.running)
1086                                 break;
1087
1088                         player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1089
1090                         LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1091
1092                         tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1093                         gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1094                         gst_event_unref(event);
1095                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1096
1097                         break;
1098                 }
1099         case GST_EVENT_QOS:
1100                 {
1101                         gdouble proportion = 0.0;
1102                         GstClockTimeDiff diff = 0;
1103                         GstClockTime timestamp = 0;
1104                         gint64 running_time_diff = -1;
1105                         GstQOSType type = 0;
1106                         GstEvent *tmpev = NULL;
1107
1108                         running_time_diff = player->gapless.segment[stream_type].base;
1109
1110                         if (running_time_diff <= 0) /* don't need to adjust */
1111                                 break;
1112
1113                         gst_event_parse_qos(event, &type, &proportion, &diff, &timestamp);
1114                         gst_event_unref(event);
1115
1116                         if (timestamp < running_time_diff) {
1117                                 LOGW("QOS event from previous group");
1118                                 ret = GST_PAD_PROBE_DROP;
1119                                 break;
1120                         }
1121
1122 #ifdef __DEBUG__
1123                         LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1124                                  " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1125                                                 stream_type, GST_TIME_ARGS(timestamp),
1126                                                 GST_TIME_ARGS(running_time_diff),
1127                                                 GST_TIME_ARGS(timestamp - running_time_diff));
1128 #endif
1129
1130                         timestamp -= running_time_diff;
1131
1132                         /* That case is invalid for QoS events */
1133                         if (diff < 0 && -diff > timestamp) {
1134                                 LOGW("QOS event from previous group");
1135                                 ret = GST_PAD_PROBE_DROP;
1136                                 break;
1137                         }
1138
1139                         tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1140                         GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1141
1142                         break;
1143                 }
1144         default:
1145                 break;
1146         }
1147
1148 ERROR:
1149         if (caps)
1150                 gst_caps_unref(caps);
1151         return ret;
1152 }
1153
1154 /* create fakesink for audio or video path without audiobin or videobin */
1155 static void
1156 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1157 {
1158         GstElement *pipeline = NULL;
1159         GstElement *fakesink = NULL;
1160         GstPad *sinkpad = NULL;
1161
1162         MMPLAYER_FENTER();
1163         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1164
1165         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1166
1167         /* fake sink */
1168         fakesink = gst_element_factory_make("fakesink", NULL);
1169         if (fakesink == NULL) {
1170                 LOGE("failed to create fakesink");
1171                 return;
1172         }
1173
1174         if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1175                 LOGE("failed to add fakesink to pipeline");
1176                 goto ERROR;
1177         }
1178
1179         /* link */
1180         sinkpad = gst_element_get_static_pad(fakesink, "sink");
1181
1182         LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1183
1184         if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1185                 LOGE("failed to link fakesink");
1186                 goto ERROR;
1187         }
1188
1189         if (strstr(name, "video")) {
1190                 if (player->v_stream_caps) {
1191                         gst_caps_unref(player->v_stream_caps);
1192                         player->v_stream_caps = NULL;
1193                 }
1194                 if (player->ini.set_dump_element_flag)
1195                         __mmplayer_add_dump_buffer_probe(player, fakesink);
1196         }
1197
1198         g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1199         gst_element_set_state(fakesink, GST_STATE_PAUSED);
1200
1201         /* store it as it's sink element */
1202         __mmplayer_add_sink(player, fakesink, FALSE);
1203
1204         if (sinkpad)
1205                 gst_object_unref(GST_OBJECT(sinkpad));
1206
1207         MMPLAYER_FLEAVE();
1208         return;
1209
1210 ERROR:
1211
1212         if (sinkpad)
1213                 gst_object_unref(GST_OBJECT(sinkpad));
1214
1215         if (fakesink) {
1216                 gst_element_set_state(fakesink, GST_STATE_NULL);
1217
1218                 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1219                         gst_object_unref(GST_OBJECT(fakesink));
1220         }
1221
1222         return;
1223 }
1224
1225 static GstElement *
1226 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1227 {
1228         GstElement *pipeline = NULL;
1229         g_autoptr(GstElement) concat = NULL;
1230         g_autoptr(GstPad) srcpad = NULL;
1231
1232         MMPLAYER_FENTER();
1233         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1234
1235         concat = gst_element_factory_make("concat", NULL);
1236         if (!concat) {
1237                 LOGE("failed to create concat");
1238                 return NULL;
1239         }
1240
1241         srcpad = gst_element_get_static_pad(concat, "src");
1242
1243         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1244         player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1245                         __mmplayer_gst_combiner_blocked, NULL, NULL);
1246         player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1247                         __mmplayer_gst_combiner_event_probe, player, NULL);
1248
1249
1250         gst_element_set_state(concat, GST_STATE_PAUSED);
1251
1252         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1253         if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1254                 LOGE("failed to add concat to pipeline");
1255                 gst_element_set_state(concat, GST_STATE_NULL);
1256                 return NULL;
1257         }
1258
1259         LOGD("Create concat [%d] element", elem_idx);
1260
1261         player->pipeline->mainbin[elem_idx].id = elem_idx;
1262         player->pipeline->mainbin[elem_idx].gst = concat;
1263
1264         MMPLAYER_FLEAVE();
1265         return g_steal_pointer(&concat);
1266 }
1267
1268 static GstElement *
1269 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1270 {
1271         GstElement *pipeline = NULL;
1272         GstElement *selector = NULL;
1273         GstPad *srcpad = NULL;
1274
1275         MMPLAYER_FENTER();
1276         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1277
1278         selector = gst_element_factory_make("input-selector", NULL);
1279         if (!selector) {
1280                 LOGE("failed to create input-selector");
1281                 return NULL;
1282         }
1283         g_object_set(selector, "sync-streams", TRUE, NULL);
1284
1285         srcpad = gst_element_get_static_pad(selector, "src");
1286
1287         LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1288         player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1289                 __mmplayer_gst_combiner_blocked, NULL, NULL);
1290         player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1291                 __mmplayer_gst_combiner_event_probe, player, NULL);
1292
1293         gst_element_set_state(selector, GST_STATE_PAUSED);
1294
1295         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1296         if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1297                 LOGE("failed to add selector to pipeline");
1298
1299                 if (player->track[stream_type].block_id != 0)
1300                   gst_pad_remove_probe(srcpad, player->track[stream_type].block_id);
1301                 player->track[stream_type].block_id = 0;
1302
1303                 if (player->track[stream_type].event_probe_id != 0)
1304                   gst_pad_remove_probe(srcpad, player->track[stream_type].event_probe_id);
1305                 player->track[stream_type].event_probe_id = 0;
1306
1307                 gst_object_unref(GST_OBJECT(srcpad));
1308
1309                 gst_element_set_state(selector, GST_STATE_NULL);
1310                 gst_object_unref(GST_OBJECT(selector));
1311                 return NULL;
1312         }
1313
1314         gst_object_unref(GST_OBJECT(srcpad));
1315
1316         player->pipeline->mainbin[elem_idx].id = elem_idx;
1317         player->pipeline->mainbin[elem_idx].gst = selector;
1318
1319         MMPLAYER_FLEAVE();
1320         return selector;
1321 }
1322
1323 void
1324 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1325 {
1326         mmplayer_t *player = (mmplayer_t *)data;
1327         GstElement *combiner = NULL;
1328         GstCaps *caps = NULL;
1329         GstStructure *str = NULL;
1330         const gchar *name = NULL;
1331         GstPad *sinkpad = NULL;
1332         gboolean first_track = FALSE;
1333         gboolean caps_ret = TRUE;
1334
1335         main_element_id_e elem_idx = MMPLAYER_M_NUM;
1336         mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1337
1338         MMPLAYER_FENTER();
1339         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1340         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1341
1342         LOGD("pad-added signal handling");
1343
1344         /* get mimetype from caps */
1345         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1346         if (!caps_ret)
1347                 goto ERROR;
1348
1349         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1350 #ifdef __DEBUG__
1351         LOGD("detected mimetype : %s", name);
1352 #endif
1353
1354         if (strstr(name, "video")) {
1355                 gint stype = 0;
1356                 gchar *caps_str = NULL;
1357
1358                 caps_str = gst_caps_to_string(caps);
1359                 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1360                         strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1361                         player->set_mode.video_zc = true;
1362
1363                 MMPLAYER_FREEIF(caps_str);
1364
1365                 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1366                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1367
1368                 LOGD("surface type : %d", stype);
1369
1370                 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1371                         __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1372                         goto DONE;
1373                 }
1374
1375                 /* in case of exporting video frame, it requires the 360 video filter.
1376                  * it will be handled in _no_more_pads(). */
1377                 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1378                         __mmplayer_gst_make_fakesink(player, pad, name);
1379                         goto DONE;
1380                 }
1381
1382                 if (MMPLAYER_USE_DECODEBIN(player)) {
1383                         LOGD("video selector is required");
1384                         elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1385                 } else {
1386                         LOGD("video concat is required");
1387                         elem_idx = MMPLAYER_M_V_CONCAT;
1388                 }
1389                 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1390         } else if (strstr(name, "audio")) {
1391                 gint samplerate = 0;
1392                 gint channels = 0;
1393
1394                 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1395                         if (player->build_audio_offload)
1396                                 player->no_more_pad = TRUE; /* remove state holder */
1397                         __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1398                         goto DONE;
1399                 }
1400
1401                 gst_structure_get_int(str, "rate", &samplerate);
1402                 gst_structure_get_int(str, "channels", &channels);
1403
1404                 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1405                         __mmplayer_gst_make_fakesink(player, pad, name);
1406                         goto DONE;
1407                 }
1408                 if (MMPLAYER_USE_DECODEBIN(player)) {
1409                         LOGD("audio selector is required");
1410                         elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1411                 } else {
1412                         LOGD("audio concat is required");
1413                         elem_idx = MMPLAYER_M_A_CONCAT;
1414                 }
1415                 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1416
1417         } else if (strstr(name, "text")) {
1418                 if (MMPLAYER_USE_DECODEBIN(player)) {
1419                         LOGD("text selector is required");
1420                         elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1421                 } else {
1422                         LOGD("text concat is required");
1423                         elem_idx = MMPLAYER_M_T_CONCAT;
1424                 }
1425                 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1426         } else {
1427                 LOGE("invalid caps info");
1428                 goto ERROR;
1429         }
1430
1431         /* check selector and create it */
1432         if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1433                 if (MMPLAYER_USE_DECODEBIN(player))
1434                         combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1435                 else
1436                         combiner = __mmplayer_gst_make_concat(player, elem_idx, stream_type);
1437
1438                 if (!combiner)
1439                         goto ERROR;
1440                 first_track = TRUE;
1441         } else {
1442                 LOGD("Combiner element is already created.");
1443         }
1444
1445         /* link */
1446         sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1447
1448         LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1449
1450         if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1451                 LOGE("failed to link combiner");
1452                 gst_object_unref(GST_OBJECT(combiner));
1453                 goto ERROR;
1454         }
1455
1456         if (first_track) {
1457                 if (MMPLAYER_USE_DECODEBIN(player)) {
1458                         LOGD("this track will be activated");
1459                         g_object_set(combiner, "active-pad", sinkpad, NULL);
1460                 }
1461         }
1462
1463         if (MMPLAYER_USE_DECODEBIN(player)) {
1464                 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1465         } else {
1466                 /* apply the text track information */
1467                 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1468                         mm_player_set_attribute((MMHandleType)player, NULL,
1469                                         "content_text_track_num", player->track[stream_type].total_track_num,
1470                                         "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1471                 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1472         }
1473
1474 DONE:
1475 ERROR:
1476
1477         if (caps)
1478                 gst_caps_unref(caps);
1479
1480         if (sinkpad) {
1481                 gst_object_unref(GST_OBJECT(sinkpad));
1482                 sinkpad = NULL;
1483         }
1484
1485         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1486         return;
1487 }
1488
1489 static gboolean
1490 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1491 {
1492         GstPad *srcpad = NULL;
1493
1494         MMPLAYER_FENTER();
1495         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1496
1497         LOGD("type %d", type);
1498
1499         if (!combiner) {
1500                 LOGD("there is no %d track", type);
1501                 return TRUE;
1502         }
1503
1504         srcpad = gst_element_get_static_pad(combiner, "src");
1505         if (!srcpad) {
1506                 LOGE("failed to get srcpad from combiner");
1507                 return FALSE;
1508         }
1509
1510         LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1511
1512         __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1513
1514         LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1515         if (player->track[type].block_id) {
1516                 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1517                 player->track[type].block_id = 0;
1518         }
1519
1520         if (srcpad) {
1521                 gst_object_unref(GST_OBJECT(srcpad));
1522                 srcpad = NULL;
1523         }
1524
1525         MMPLAYER_FLEAVE();
1526         return TRUE;
1527 }
1528
1529 static void
1530 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1531 {
1532         gint active_index = 0;
1533
1534         MMPLAYER_FENTER();
1535         MMPLAYER_RETURN_IF_FAIL(player);
1536
1537         LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1538
1539         /* change track to active pad */
1540         active_index = player->track[type].active_track_index;
1541         if ((active_index != DEFAULT_TRACK_INDEX) &&
1542                 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1543                 LOGW("failed to change %d type track to %d", type, active_index);
1544                 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1545                 return;
1546         }
1547
1548         if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1549                 mm_player_set_attribute((MMHandleType)player, NULL,
1550                                 "content_text_track_num", player->track[type].total_track_num,
1551                                 "current_text_track_index", player->track[type].active_track_index, NULL);
1552
1553         MMPLAYER_FLEAVE();
1554         return;
1555 }
1556
1557 static gboolean
1558 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1559 {
1560         MMPLAYER_FENTER();
1561         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1562
1563         if (!audio_selector) {
1564                 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1565
1566                 /* in case the source is changed, output can be changed. */
1567                 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1568                         LOGD("remove previous audiobin if it exist");
1569
1570                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1571                         __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1572
1573                         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1574                         MMPLAYER_FREEIF(player->pipeline->audiobin);
1575                 }
1576
1577                 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1578                         _mmplayer_pipeline_complete(NULL, player);
1579
1580                 return TRUE;
1581         }
1582
1583         /* apply the audio track information */
1584         if (MMPLAYER_USE_DECODEBIN(player))
1585                 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1586
1587         /* create audio sink path */
1588         if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1589                 LOGE("failed to create audio sink path");
1590                 return FALSE;
1591         }
1592
1593         MMPLAYER_FLEAVE();
1594         return TRUE;
1595 }
1596
1597 static gboolean
1598 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1599 {
1600         MMPLAYER_FENTER();
1601         MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1602
1603         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1604                 LOGD("text path is not supported");
1605                 return TRUE;
1606         }
1607
1608         /* apply the text track information */
1609         __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1610
1611         if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1612                 player->has_closed_caption = TRUE;
1613
1614         /* create text decode path */
1615         player->no_more_pad = TRUE;
1616
1617         if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1618                 LOGE("failed to create text sink path");
1619                 return FALSE;
1620         }
1621
1622         MMPLAYER_FLEAVE();
1623         return TRUE;
1624 }
1625
1626 static gboolean
1627 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1628 {
1629         gint64 dur_bytes = 0L;
1630
1631         MMPLAYER_FENTER();
1632         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1633                 player->pipeline->mainbin && player->streamer, FALSE);
1634
1635         if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1636                 LOGE("fail to get duration.");
1637
1638         /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1639          * use file information was already set on Q2 when it was created. */
1640         _mm_player_streaming_set_queue2(player->streamer,
1641                                         player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1642                                         TRUE,                                                           /* use_buffering */
1643                                         MUXED_BUFFER_TYPE_MAX,                          /* use previous buffer type setting */
1644                                         ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1645
1646         MMPLAYER_FLEAVE();
1647         return TRUE;
1648 }
1649
1650 void
1651 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1652 {
1653         mmplayer_t *player = NULL;
1654         GstElement *video_selector = NULL;
1655         GstElement *audio_selector = NULL;
1656         GstElement *text_selector = NULL;
1657
1658         MMPLAYER_FENTER();
1659         player = (mmplayer_t *)data;
1660
1661         LOGD("no-more-pad signal handling");
1662
1663         if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1664                 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1665                 LOGW("player is shutting down");
1666                 goto EXIT;
1667         }
1668
1669         if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1670                 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1671                 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1672                 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1673                         LOGE("failed to set queue2 buffering");
1674                         goto EXIT;
1675                 }
1676         }
1677
1678         video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1679         audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1680         text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1681
1682         if (!video_selector && !audio_selector && !text_selector) {
1683                 LOGW("there is no selector");
1684                 player->no_more_pad = TRUE;
1685                 goto EXIT;
1686         }
1687
1688         /* create video path followed by video-select */
1689         if (video_selector && !audio_selector && !text_selector)
1690                 player->no_more_pad = TRUE;
1691
1692         if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1693                 goto EXIT;
1694
1695         /* create audio path followed by audio-select */
1696         if (audio_selector && !text_selector)
1697                 player->no_more_pad = TRUE;
1698
1699         if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1700                 goto EXIT;
1701
1702         /* create text path followed by text-select */
1703         __mmplayer_create_text_sink_path(player, text_selector);
1704
1705 EXIT:
1706         _mmplayer_set_reconfigure_state(player, FALSE);
1707         MMPLAYER_FLEAVE();
1708 }
1709
1710 static gboolean
1711 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1712 {
1713         gboolean ret = FALSE;
1714         GstElement *pipeline = NULL;
1715         GstPad *sinkpad = NULL;
1716
1717         MMPLAYER_FENTER();
1718         MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1719         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1720
1721         pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1722
1723         sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1724         if (!sinkpad) {
1725                 LOGE("failed to get pad from sinkbin");
1726                 goto EXIT;
1727         }
1728
1729         if (reusing) {
1730                 /* link only */
1731                 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1732                         LOGE("failed to link sinkbin for reusing");
1733                         goto EXIT; /* exit either pass or fail */
1734                 }
1735         } else {
1736                 /* warm up */
1737                 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1738                         LOGE("failed to set state(READY) to sinkbin");
1739                         goto EXIT;
1740                 }
1741
1742                 /* add */
1743                 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1744                         LOGE("failed to add sinkbin to pipeline");
1745                         goto EXIT;
1746                 }
1747
1748                 /* link */
1749                 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1750                         LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1751                         goto EXIT;
1752                 }
1753
1754                 /* run */
1755                 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1756                         LOGE("failed to set state(PAUSED) to sinkbin");
1757                         goto EXIT;
1758                 }
1759         }
1760
1761         ret = TRUE;
1762
1763 EXIT:
1764         if (sinkpad)
1765                 gst_object_unref(GST_OBJECT(sinkpad));
1766         sinkpad = NULL;
1767
1768         MMPLAYER_FLEAVE();
1769         return ret;
1770 }
1771
1772 static void
1773 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1774 {
1775         mmplayer_t *player = NULL;
1776         GstCaps *caps = NULL;
1777         gchar *caps_str = NULL;
1778         GstStructure *str = NULL;
1779         const gchar *name = NULL;
1780         GstElement *sinkbin = NULL;
1781         gboolean reusing = FALSE;
1782         gboolean caps_ret = TRUE;
1783         gchar *sink_pad_name = "sink";
1784
1785         /* check handles */
1786         player = (mmplayer_t *)data;
1787
1788         MMPLAYER_FENTER();
1789         MMPLAYER_RETURN_IF_FAIL(elem && pad);
1790         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1791         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1792         if (!caps_ret) {
1793                 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1794                 if (!caps_ret)
1795                         goto ERROR;
1796                 if (caps)
1797                         gst_caps_unref(caps);
1798                 caps = gst_caps_ref(ref_caps);
1799         }
1800
1801         caps_str = gst_caps_to_string(caps);
1802 #ifdef __DEBUG__
1803         LOGD("detected mimetype : %s", name);
1804 #endif
1805         if (strstr(name, "audio")) {
1806                 if (player->pipeline->audiobin == NULL) {
1807                         const gchar *audio_format = gst_structure_get_string(str, "format");
1808                         if (audio_format) {
1809                                 LOGD("original audio format %s", audio_format);
1810                                 mm_player_set_attribute((MMHandleType)player, NULL,
1811                                                 "content_audio_format", audio_format, strlen(audio_format), NULL);
1812                         }
1813
1814                         if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1815                                 LOGE("failed to create audiobin. continuing without audio");
1816                                 goto ERROR;
1817                         }
1818
1819                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1820                         LOGD("creating audiobin success");
1821                 } else {
1822                         reusing = TRUE;
1823                         sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1824                         LOGD("reusing audiobin");
1825                         _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1826                 }
1827         } else if (strstr(name, "video")) {
1828                 /* 1. zero copy is updated at _decode_pad_added()
1829                  * 2. NULL surface type is handled in _decode_pad_added() */
1830                 LOGD("zero copy %d", player->set_mode.video_zc);
1831                 if (player->pipeline->videobin == NULL) {
1832                         int surface_type = 0;
1833                         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1834                         LOGD("display_surface_type (%d)", surface_type);
1835
1836                         if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1837                                 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1838                                 LOGE("failed to acquire video overlay resource");
1839                                 goto ERROR;
1840                         }
1841
1842                         player->interrupted_by_resource = FALSE;
1843
1844                         if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1845                                 LOGE("failed to create videobin. continuing without video");
1846                                 goto ERROR;
1847                         }
1848
1849                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1850                         LOGD("creating videosink bin success");
1851                 } else {
1852                         reusing = TRUE;
1853                         sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1854                         LOGD("re-using videobin");
1855                         _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1856                 }
1857         } else if (strstr(name, "text")) {
1858                 if (player->pipeline->textbin == NULL) {
1859                         if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1860                                 LOGE("failed to create text sink bin. continuing without text");
1861                                 goto ERROR;
1862                         }
1863
1864                         sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1865                         player->textsink_linked  = 1;
1866                         LOGD("creating textsink bin success");
1867                 } else {
1868                         if (!player->textsink_linked) {
1869                                 LOGD("re-using textbin");
1870                                 reusing = TRUE;
1871                                 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1872                                 player->textsink_linked  = 1;
1873                         } else {
1874                                 /* linked textbin exist which means that the external subtitle path exist already */
1875                                 LOGW("ignoring internal subtitle since external subtitle is available");
1876                         }
1877                 }
1878                 sink_pad_name = "text_sink";
1879         } else {
1880                 LOGW("unknown mime type %s, ignoring it", name);
1881                 goto ERROR;
1882         }
1883
1884         if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1885                 goto ERROR;
1886
1887         LOGD("[handle: %p] success to create and link sink bin", player);
1888
1889         /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1890          * streaming task. if the task blocked, then buffer will not flow to the next element
1891          *(autoplugging element). so this is special hack for streaming. please try to remove it
1892          */
1893         /* dec stream count. we can remove fakesink if it's zero */
1894         if (player->num_dynamic_pad)
1895                 player->num_dynamic_pad--;
1896
1897         LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1898
1899         if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1900                 _mmplayer_pipeline_complete(NULL, player);
1901
1902 ERROR:
1903
1904         MMPLAYER_FREEIF(caps_str);
1905
1906         if (caps)
1907                 gst_caps_unref(caps);
1908
1909         return;
1910 }
1911
1912 static gboolean
1913 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1914 {
1915         int required_angle = 0; /* Angle required for straight view */
1916         int rotation_angle = 0;
1917
1918         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1919         MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1920
1921         /* Counter clockwise */
1922         switch (orientation) {
1923         case 0:
1924                 required_angle = 0;
1925                 break;
1926         case 90:
1927                 required_angle = 270;
1928                 break;
1929         case 180:
1930                 required_angle = 180;
1931                 break;
1932         case 270:
1933                 required_angle = 90;
1934                 break;
1935         }
1936
1937         rotation_angle = display_angle + required_angle;
1938         if (rotation_angle >= 360)
1939                 rotation_angle -= 360;
1940
1941         /* check if supported or not */
1942         if (rotation_angle % 90) {
1943                 LOGD("not supported rotation angle = %d", rotation_angle);
1944                 return FALSE;
1945         }
1946
1947         switch (rotation_angle) {
1948         case 0:
1949                 *value = MM_DISPLAY_ROTATION_NONE;
1950                 break;
1951         case 90:
1952                 *value = MM_DISPLAY_ROTATION_90;
1953                 break;
1954         case 180:
1955                 *value = MM_DISPLAY_ROTATION_180;
1956                 break;
1957         case 270:
1958                 *value = MM_DISPLAY_ROTATION_270;
1959                 break;
1960         }
1961
1962         LOGD("setting rotation property value : %d", *value);
1963
1964         return TRUE;
1965 }
1966
1967 int
1968 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1969 {
1970         int display_rotation = 0;
1971         gchar *org_orient = NULL;
1972         MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1973
1974         if (!attrs) {
1975                 LOGE("cannot get content attribute");
1976                 return MM_ERROR_PLAYER_INTERNAL;
1977         }
1978
1979         if (display_angle) {
1980                 /* update user rotation */
1981                 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1982
1983                 /* Counter clockwise */
1984                 switch (display_rotation) {
1985                 case MM_DISPLAY_ROTATION_NONE:
1986                         *display_angle = 0;
1987                         break;
1988                 case MM_DISPLAY_ROTATION_90:
1989                         *display_angle = 90;
1990                         break;
1991                 case MM_DISPLAY_ROTATION_180:
1992                         *display_angle = 180;
1993                         break;
1994                 case MM_DISPLAY_ROTATION_270:
1995                         *display_angle = 270;
1996                         break;
1997                 default:
1998                         LOGW("wrong angle type : %d", display_rotation);
1999                         break;
2000                 }
2001                 LOGD("check user angle: %d", *display_angle);
2002         }
2003
2004         if (orientation) {
2005                 /* Counter clockwise */
2006                 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2007
2008                 if (org_orient) {
2009                         if (!strcmp(org_orient, "rotate-90"))
2010                                 *orientation = 90;
2011                         else if (!strcmp(org_orient, "rotate-180"))
2012                                 *orientation = 180;
2013                         else if (!strcmp(org_orient, "rotate-270"))
2014                                 *orientation = 270;
2015                         else
2016                                 LOGD("original rotation is %s", org_orient);
2017                 } else {
2018                         LOGD("content_video_orientation get fail");
2019                 }
2020
2021                 LOGD("check orientation: %d", *orientation);
2022         }
2023
2024         return MM_ERROR_NONE;
2025 }
2026
2027 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2028 {
2029         int rotation_value = 0;
2030         int orientations = 0; // current supported angle values are 0, 90, 180, 270
2031         int display_angle = 0;
2032         MMPLAYER_FENTER();
2033
2034         /* check video sinkbin is created */
2035         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2036                 return;
2037
2038         _mmplayer_get_video_angle(player, &display_angle, &orientations);
2039
2040         /* get rotation value to set */
2041         __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2042         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2043         LOGD("set video param : rotate %d", rotation_value);
2044 }
2045
2046 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2047 {
2048         MMHandleType attrs = 0;
2049         int visible = 0;
2050         MMPLAYER_FENTER();
2051
2052         /* check video sinkbin is created */
2053         if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2054                 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2055                 return;
2056
2057         attrs = MMPLAYER_GET_ATTRS(player);
2058         MMPLAYER_RETURN_IF_FAIL(attrs);
2059
2060         mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2061         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2062         LOGD("set video param : visible %d", visible);
2063 }
2064
2065 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2066 {
2067         MMHandleType attrs = 0;
2068         int display_method = 0;
2069         MMPLAYER_FENTER();
2070
2071         /* check video sinkbin is created */
2072         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2073                 return;
2074
2075         attrs = MMPLAYER_GET_ATTRS(player);
2076         MMPLAYER_RETURN_IF_FAIL(attrs);
2077
2078         mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2079         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2080         LOGD("set video param : method %d", display_method);
2081 }
2082
2083 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2084 {
2085         MMHandleType attrs = 0;
2086         int handle = 0;
2087         MMPLAYER_FENTER();
2088
2089         /* check video sinkbin is created */
2090         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2091                 return;
2092
2093         attrs = MMPLAYER_GET_ATTRS(player);
2094         MMPLAYER_RETURN_IF_FAIL(attrs);
2095
2096         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2097         MMPLAYER_RETURN_IF_FAIL(handle);
2098
2099         gst_video_overlay_set_video_roi_area(
2100                  GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2101                  player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2102         LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2103                 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2104 }
2105
2106 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2107 {
2108         MMHandleType attrs = 0;
2109         int handle = 0;
2110         /*set wl_display*/
2111         int win_roi_x = 0;
2112         int win_roi_y = 0;
2113         int win_roi_width = 0;
2114         int win_roi_height = 0;
2115         MMPLAYER_FENTER();
2116
2117         /* check video sinkbin is created */
2118         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2119                 return;
2120
2121         attrs = MMPLAYER_GET_ATTRS(player);
2122         MMPLAYER_RETURN_IF_FAIL(attrs);
2123
2124         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2125         MMPLAYER_RETURN_IF_FAIL(handle);
2126
2127         /* It should be set after setting window */
2128         mm_attrs_multiple_get(attrs, NULL,
2129                                 "display_win_roi_x", &win_roi_x,
2130                                 "display_win_roi_y", &win_roi_y,
2131                                 "display_win_roi_width", &win_roi_width,
2132                                 "display_win_roi_height", &win_roi_height, NULL);
2133
2134         /* After setting window handle, set display roi area */
2135         gst_video_overlay_set_display_roi_area(
2136                  GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2137                  win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2138         LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2139                 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2140 }
2141
2142 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2143 {
2144         MMHandleType attrs = 0;
2145         gchar *handle = NULL;
2146
2147         /* check video sinkbin is created */
2148         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2149                 return;
2150
2151         attrs = MMPLAYER_GET_ATTRS(player);
2152         MMPLAYER_RETURN_IF_FAIL(attrs);
2153
2154         /* common case if using overlay surface */
2155         mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2156         MMPLAYER_RETURN_IF_FAIL(handle);
2157
2158         gst_video_overlay_set_wl_window_exported_shell_handle(
2159                         GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2160                         handle);
2161         LOGD("set video param: exported_shell_handle (%s)", handle);
2162 }
2163
2164 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2165 {
2166         MMHandleType attrs = 0;
2167         int handle = 0;
2168
2169         /* check video sinkbin is created */
2170         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2171                 return;
2172
2173         attrs = MMPLAYER_GET_ATTRS(player);
2174         MMPLAYER_RETURN_IF_FAIL(attrs);
2175
2176         /* common case if using overlay surface */
2177         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2178         MMPLAYER_RETURN_IF_FAIL(handle);
2179
2180         /* default is using wl_surface_id */
2181         LOGD("set video param : wl_surface_id %d", handle);
2182         gst_video_overlay_set_wl_window_wl_surface_id(
2183                         GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2184                         handle);
2185 }
2186
2187 int
2188 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2189 {
2190         gboolean update_all_param = FALSE;
2191         int curr_type = MM_DISPLAY_SURFACE_NUM;
2192
2193         MMPLAYER_FENTER();
2194
2195         if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2196                 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2197                 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2198                 LOGW("videosink is not ready yet");
2199                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2200         }
2201
2202         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2203
2204         if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2205                 LOGE("current type(%d) is wrong", curr_type);
2206                 return MM_ERROR_PLAYER_INTERNAL;
2207         }
2208
2209         if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2210                 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2211                 return MM_ERROR_PLAYER_INTERNAL;
2212         }
2213
2214         LOGD("param_name : %s", param_name);
2215         if (!g_strcmp0(param_name, "update_all_param"))
2216                 update_all_param = TRUE;
2217
2218         if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2219                 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2220                 MMPLAYER_FLEAVE();
2221                 return MM_ERROR_NONE;
2222         }
2223         if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2224                 __mmplayer_video_param_set_display_overlay(player);
2225         if (update_all_param || !g_strcmp0(param_name, "display_method"))
2226                 __mmplayer_video_param_set_display_method(player);
2227         if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2228                 __mmplayer_video_param_set_display_visible(player);
2229         if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2230                 __mmplayer_video_param_set_display_rotation(player);
2231         if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2232                 __mmplayer_video_param_set_roi_area(player);
2233         if (update_all_param)
2234                 __mmplayer_video_param_set_video_roi_area(player);
2235
2236         MMPLAYER_FLEAVE();
2237         return MM_ERROR_NONE;
2238 }
2239
2240 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2241 {
2242         gboolean disable_overlay = FALSE;
2243
2244         MMPLAYER_FENTER();
2245         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2246                                                                 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2247                                                                 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2248
2249         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2250                 LOGW("Display control is not supported");
2251                 return MM_ERROR_PLAYER_INTERNAL;
2252         }
2253
2254         g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2255
2256         if (disable == (bool)disable_overlay) {
2257                 LOGE("It's the same with current setting: (%d)", disable);
2258                 return MM_ERROR_NONE;
2259         }
2260
2261         if (disable) {
2262                 LOGE("disable overlay");
2263                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2264
2265                 /* release overlay resource */
2266                 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2267                         LOGE("failed to release overlay resource");
2268                         return MM_ERROR_PLAYER_INTERNAL;
2269                 }
2270         } else {
2271                 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2272                         LOGE("failed to acquire video overlay resource");
2273                         return MM_ERROR_PLAYER_INTERNAL;
2274                 }
2275                 player->interrupted_by_resource = FALSE;
2276
2277                 LOGD("enable overlay");
2278                 __mmplayer_video_param_set_display_overlay(player);
2279                 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2280                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2281         }
2282
2283         MMPLAYER_FLEAVE();
2284         return MM_ERROR_NONE;
2285 }
2286
2287 int
2288 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2289 {
2290         int ret = MM_ERROR_NONE;
2291         mmplayer_t *player = (mmplayer_t *)hplayer;
2292
2293         MMPLAYER_FENTER();
2294         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2295
2296         if (MMPLAYER_USE_DECODEBIN(player)) {
2297                 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2298                 goto EXIT;
2299         }
2300
2301         if (audio_only) {
2302                 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2303                                                                         player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2304                                                                         MM_ERROR_PLAYER_NO_OP); /* invalid op */
2305
2306                 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2307
2308                 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2309
2310                 /* release decoder resource */
2311                 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2312                         LOGE("failed to release video decoder resources");
2313                         return MM_ERROR_PLAYER_INTERNAL;
2314                 }
2315                 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2316         } else {
2317                 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2318         }
2319
2320 EXIT:
2321         mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2322
2323         MMPLAYER_FLEAVE();
2324         return ret;
2325 }
2326
2327 int
2328 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2329 {
2330         GList *bucket = element_bucket;
2331         mmplayer_gst_element_t *element = NULL;
2332         mmplayer_gst_element_t *prv_element = NULL;
2333         GstElement *tee_element = NULL;
2334         gint successful_link_count = 0;
2335
2336         MMPLAYER_FENTER();
2337
2338         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2339
2340         prv_element = (mmplayer_gst_element_t *)bucket->data;
2341         bucket = bucket->next;
2342
2343         for (; bucket; bucket = bucket->next) {
2344                 element = (mmplayer_gst_element_t *)bucket->data;
2345
2346                 if (element && element->gst) {
2347                         if (prv_element && prv_element->gst) {
2348                                 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2349                                         if (tee_element) {
2350                                                 prv_element->gst = tee_element;
2351                                         } else {
2352                                                 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2353                                                         GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2354                                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2355                                                 return -1;
2356                                         }
2357                                 }
2358                                 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2359                                         LOGD("linking [%s] to [%s] success",
2360                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2361                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2362                                         successful_link_count++;
2363                                         if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2364                                                 LOGD("keep audio-tee element for next audio pipeline branch");
2365                                                 tee_element = prv_element->gst;
2366                                         }
2367                                 } else {
2368                                         LOGD("linking [%s] to [%s] failed",
2369                                                 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2370                                                 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2371                                         return -1;
2372                                 }
2373                         }
2374                 }
2375
2376                 prv_element = element;
2377         }
2378
2379         MMPLAYER_FLEAVE();
2380
2381         return successful_link_count;
2382 }
2383
2384 int
2385 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2386 {
2387         GList *bucket = element_bucket;
2388         mmplayer_gst_element_t *element = NULL;
2389         int successful_add_count = 0;
2390
2391         MMPLAYER_FENTER();
2392
2393         MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2394         MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2395
2396         for (; bucket; bucket = bucket->next) {
2397                 element = (mmplayer_gst_element_t *)bucket->data;
2398
2399                 if (element && element->gst) {
2400                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2401                                 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s]  to bin [%s] failed",
2402                                         GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2403                                         GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2404                                 return 0;
2405                         }
2406                         successful_add_count++;
2407                 }
2408         }
2409
2410         MMPLAYER_FLEAVE();
2411
2412         return successful_add_count;
2413 }
2414
2415 static void
2416 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2417 {
2418         mmplayer_t *player = (mmplayer_t *)data;
2419         GstCaps *caps = NULL;
2420         GstStructure *str = NULL;
2421         const char *name;
2422         gboolean caps_ret = TRUE;
2423
2424         MMPLAYER_FENTER();
2425
2426         MMPLAYER_RETURN_IF_FAIL(pad);
2427         MMPLAYER_RETURN_IF_FAIL(unused);
2428         MMPLAYER_RETURN_IF_FAIL(data);
2429
2430         MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2431         if (!caps_ret)
2432                 goto ERROR;
2433
2434         LOGD("name = %s", name);
2435
2436         if (strstr(name, "audio")) {
2437                 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2438
2439                 if (player->audio_stream_changed_cb) {
2440                         LOGE("call the audio stream changed cb");
2441                         player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2442                 }
2443         } else if (strstr(name, "video")) {
2444                 if ((name = gst_structure_get_string(str, "format")))
2445                         player->set_mode.video_zc = name[0] == 'S';
2446
2447                 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2448                 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2449         } else {
2450                 LOGW("invalid caps info");
2451         }
2452
2453 ERROR:
2454         if (caps)
2455                 gst_caps_unref(caps);
2456
2457         MMPLAYER_FLEAVE();
2458
2459         return;
2460 }
2461
2462 void
2463 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2464 {
2465         GList *l = NULL;
2466
2467         MMPLAYER_FENTER();
2468         MMPLAYER_RETURN_IF_FAIL(player);
2469
2470         if (player->audio_stream_buff_list) {
2471                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2472                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2473                         if (tmp) {
2474                                 if (send_all) {
2475                                         LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2476                                         __mmplayer_audio_stream_send_data(player, tmp);
2477                                 }
2478                                 MMPLAYER_FREEIF(tmp->pcm_data);
2479                                 MMPLAYER_FREEIF(tmp);
2480                         }
2481                 }
2482                 g_list_free(player->audio_stream_buff_list);
2483                 player->audio_stream_buff_list = NULL;
2484         }
2485
2486         MMPLAYER_FLEAVE();
2487 }
2488
2489 static void
2490 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2491 {
2492         mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2493
2494         MMPLAYER_FENTER();
2495         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2496
2497         audio_stream.bitrate = a_buffer->bitrate;
2498         audio_stream.channel = a_buffer->channel;
2499         audio_stream.channel_mask = a_buffer->channel_mask;
2500         audio_stream.data_size = a_buffer->data_size;
2501         audio_stream.data = a_buffer->pcm_data;
2502         audio_stream.pcm_format = a_buffer->pcm_format;
2503 #ifdef __DEBUG__
2504         LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2505 #endif
2506         player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2507
2508         MMPLAYER_FLEAVE();
2509 }
2510
2511 static void
2512 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2513 {
2514         mmplayer_t *player = (mmplayer_t *)data;
2515         const gchar *pcm_format = NULL;
2516         gint channel = 0;
2517         gint rate = 0;
2518         guint64 channel_mask = 0;
2519         void *a_data = NULL;
2520         gint a_size = 0;
2521         mmplayer_audio_stream_buff_t *a_buffer = NULL;
2522         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2523         GList *l = NULL;
2524
2525         MMPLAYER_FENTER();
2526         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2527
2528         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2529         a_data = mapinfo.data;
2530         a_size = mapinfo.size;
2531
2532         GstCaps *caps = gst_pad_get_current_caps(pad);
2533         GstStructure *structure = gst_caps_get_structure(caps, 0);
2534 #ifdef __DEBUG__
2535         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2536 #endif
2537         pcm_format = gst_structure_get_string(structure, "format");
2538         gst_structure_get_int(structure, "rate", &rate);
2539         gst_structure_get_int(structure, "channels", &channel);
2540         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2541         gst_caps_unref(GST_CAPS(caps));
2542
2543         /* In case of the sync is false, use buffer list.              *
2544          * The num of buffer list depends on the num of audio channels */
2545         if (player->audio_stream_buff_list) {
2546                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2547                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2548                         if (tmp) {
2549                                 if (channel_mask == tmp->channel_mask) {
2550 #ifdef __DEBUG__
2551                                         LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2552 #endif
2553                                         if (tmp->data_size + a_size < tmp->buff_size) {
2554                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2555                                                 tmp->data_size += a_size;
2556                                         } else {
2557                                                 /* send data to client */
2558                                                 __mmplayer_audio_stream_send_data(player, tmp);
2559
2560                                                 if (a_size > tmp->buff_size) {
2561                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2562                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2563                                                         if (tmp->pcm_data == NULL) {
2564                                                                 LOGE("failed to realloc data.");
2565                                                                 goto DONE;
2566                                                         }
2567                                                         tmp->buff_size = a_size;
2568                                                 }
2569                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2570                                                 memcpy(tmp->pcm_data, a_data, a_size);
2571                                                 tmp->data_size = a_size;
2572                                         }
2573                                         goto DONE;
2574                                 }
2575                         } else {
2576                                 LOGE("data is empty in list.");
2577                                 goto DONE;
2578                         }
2579                 }
2580         }
2581
2582         /* create new audio stream data for newly found audio channel */
2583         a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2584         if (a_buffer == NULL) {
2585                 LOGE("failed to alloc data.");
2586                 goto DONE;
2587         }
2588         a_buffer->bitrate = rate;
2589         a_buffer->channel = channel;
2590         a_buffer->channel_mask = channel_mask;
2591         a_buffer->data_size = a_size;
2592         a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2593
2594         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2595                 /* If sync is FALSE, use buffer list to reduce the IPC. */
2596                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2597                 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2598                 if (a_buffer->pcm_data == NULL) {
2599                         LOGE("failed to alloc data.");
2600                         MMPLAYER_FREEIF(a_buffer);
2601                         goto DONE;
2602                 }
2603                 memcpy(a_buffer->pcm_data, a_data, a_size);
2604 #ifdef __DEBUG__
2605                 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2606 #endif
2607                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2608         } else {
2609                 /* If sync is TRUE, send data directly. */
2610                 a_buffer->pcm_data = a_data;
2611                 __mmplayer_audio_stream_send_data(player, a_buffer);
2612                 MMPLAYER_FREEIF(a_buffer);
2613         }
2614
2615 DONE:
2616         gst_buffer_unmap(buffer, &mapinfo);
2617         MMPLAYER_FLEAVE();
2618 }
2619
2620 static void
2621 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2622 {
2623         mmplayer_t *player = (mmplayer_t *)data;
2624         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2625         GstPad *sinkpad = NULL;
2626         GstElement *queue = NULL, *sink = NULL;
2627
2628         MMPLAYER_FENTER();
2629         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2630
2631         queue = gst_element_factory_make("queue", NULL);
2632         if (queue == NULL) {
2633                 LOGD("fail make queue");
2634                 goto ERROR;
2635         }
2636
2637         sink = gst_element_factory_make("fakesink", NULL);
2638         if (sink == NULL) {
2639                 LOGD("fail make fakesink");
2640                 goto ERROR;
2641         }
2642
2643         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2644
2645         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2646                 LOGW("failed to link queue & sink");
2647                 goto ERROR;
2648         }
2649
2650         sinkpad = gst_element_get_static_pad(queue, "sink");
2651
2652         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2653                 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2654                 goto ERROR;
2655         }
2656
2657         LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2658
2659         gst_object_unref(sinkpad);
2660         if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2661                 g_object_set(sink, "sync", TRUE, NULL);
2662         g_object_set(sink, "signal-handoffs", TRUE, NULL);
2663
2664         /* keep the first sink reference only */
2665         if (!audiobin[MMPLAYER_A_SINK].gst) {
2666                 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2667                 audiobin[MMPLAYER_A_SINK].gst = sink;
2668         }
2669
2670
2671         _mmplayer_add_signal_connection(player,
2672                 G_OBJECT(sink),
2673                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2674                 "handoff",
2675                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2676                 (gpointer)player);
2677
2678         __mmplayer_add_sink(player, sink, FALSE);
2679
2680         if (!gst_element_sync_state_with_parent(queue)) {
2681                 LOGE("failed to sync state");
2682                 goto ERROR;
2683         }
2684
2685         if (!gst_element_sync_state_with_parent(sink)) {
2686                 LOGE("failed to sync state");
2687                 goto ERROR;
2688         }
2689
2690         MMPLAYER_FLEAVE();
2691         return;
2692
2693 ERROR:
2694         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2695         if (queue) {
2696                 gst_object_unref(GST_OBJECT(queue));
2697                 queue = NULL;
2698         }
2699         if (sink) {
2700                 gst_object_unref(GST_OBJECT(sink));
2701                 sink = NULL;
2702         }
2703         if (sinkpad) {
2704                 gst_object_unref(GST_OBJECT(sinkpad));
2705                 sinkpad = NULL;
2706         }
2707
2708         return;
2709 }
2710
2711 void
2712 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2713 {
2714         mmplayer_t *player = (mmplayer_t *)data;
2715
2716         MMPLAYER_FENTER();
2717         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2718
2719         player->no_more_pad = TRUE;
2720         _mmplayer_pipeline_complete(NULL, player);
2721
2722         MMPLAYER_FLEAVE();
2723         return;
2724 }
2725
2726 void
2727 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2728 {
2729         #define MAX_PROPS_LEN 128
2730         mmplayer_gst_element_t *audiobin = NULL;
2731         gint latency_mode = 0;
2732         gchar *stream_type = NULL;
2733         gchar *latency = NULL;
2734         gint stream_id = 0;
2735         gchar stream_props[MAX_PROPS_LEN] = {0,};
2736         GstStructure *props = NULL;
2737
2738         /* set volume table
2739          * It should be set after player creation through attribute.
2740          * But, it can not be changed during playing.
2741          */
2742         MMPLAYER_FENTER();
2743         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2744
2745         audiobin = player->pipeline->audiobin;
2746
2747         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2748         if (player->sound.mute) {
2749                 LOGD("mute enabled");
2750                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2751         }
2752
2753         mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2754         mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2755
2756         if (!stream_type)
2757                 snprintf(stream_props, sizeof(stream_props) - 1,
2758                                 "props,application.process.id.origin=%d", player->client_pid);
2759         else
2760                 snprintf(stream_props, sizeof(stream_props) - 1,
2761                                 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2762                                 stream_type, stream_id, player->client_pid);
2763
2764         props = gst_structure_from_string(stream_props, NULL);
2765         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2766         LOGI("props result[%s].", stream_props);
2767         gst_structure_free(props);
2768
2769         mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2770
2771         switch (latency_mode) {
2772         case AUDIO_LATENCY_MODE_LOW:
2773                 latency = g_strdup("low");
2774                 break;
2775         case AUDIO_LATENCY_MODE_MID:
2776                 latency = g_strdup("mid");
2777                 break;
2778         case AUDIO_LATENCY_MODE_HIGH:
2779                 latency = g_strdup("high");
2780                 break;
2781         default:
2782                 latency = g_strdup("mid");
2783                 break;
2784         };
2785
2786         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2787
2788         LOGD("audiosink property - latency=%s", latency);
2789
2790         MMPLAYER_FREEIF(latency);
2791
2792         MMPLAYER_FLEAVE();
2793 }
2794
2795 int
2796 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2797 {
2798         mmplayer_gst_element_t *audiobin = NULL;
2799
2800         MMPLAYER_FENTER();
2801         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2802                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2803
2804         audiobin = player->pipeline->audiobin;
2805
2806         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2807         if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2808                 LOGE("failed to create media stream info");
2809                 return MM_ERROR_PLAYER_INTERNAL;
2810         }
2811
2812         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2813
2814         if (player->video360_yaw_radians <= M_PI &&
2815                         player->video360_yaw_radians >= -M_PI &&
2816                         player->video360_pitch_radians <= M_PI_2 &&
2817                         player->video360_pitch_radians >= -M_PI_2) {
2818                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2819                                 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2820                                 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2821         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2822                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2823                                 "source-orientation-y", player->video360_metadata.init_view_heading,
2824                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2825         }
2826
2827         MMPLAYER_FLEAVE();
2828         return MM_ERROR_NONE;
2829 }
2830
2831 static int
2832 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2833 {
2834         mmplayer_gst_element_t *audiobin = NULL;
2835         GstPad *sink_pad = NULL;
2836         GstCaps *acaps = NULL;
2837         gint channels = 0;
2838         int pitch_control = 0;
2839         double pitch_value = 1.0;
2840
2841         MMPLAYER_FENTER();
2842         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2843                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2844
2845         audiobin = player->pipeline->audiobin;
2846
2847         LOGD("make element for normal audio playback");
2848
2849         /* audio bin structure for playback. {} means optional.
2850            optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2851
2852          * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2853                         {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2854          */
2855
2856         /* for pitch control */
2857         mm_attrs_multiple_get(player->attrs, NULL,
2858                                 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2859                                 MM_PLAYER_PITCH_VALUE, &pitch_value,
2860                                 NULL);
2861
2862         LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2863         if (pitch_control && (player->videodec_linked == 0)) {
2864                 GstElementFactory *factory;
2865
2866                 factory = gst_element_factory_find("pitch");
2867                 if (factory) {
2868                         gst_object_unref(factory);
2869
2870                         /* converter */
2871                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2872
2873                         /* pitch */
2874                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2875                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2876                 } else {
2877                         LOGW("there is no pitch element");
2878                 }
2879         }
2880
2881         /* converter */
2882         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2883
2884         /* replaygain volume */
2885         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2886         if (player->sound.rg_enable)
2887                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2888         else
2889                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2890
2891         /* resampler */
2892         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", *bucket, player);
2893
2894         if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2895                 /* currently, only openalsink uses volume element */
2896                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2897                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2898
2899                 if (player->sound.mute) {
2900                         LOGD("mute enabled");
2901                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2902                 }
2903         }
2904
2905         mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2906
2907         /* audio effect element. if audio effect is enabled */
2908         if ((strcmp(player->ini.audioeffect_element, ""))
2909                 && (channels <= 2)
2910                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2911                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2912
2913                 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2914
2915                 if ((!player->bypass_audio_effect)
2916                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2917                         if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2918                                 if (!_mmplayer_audio_effect_custom_apply(player))
2919                                         LOGI("apply audio effect(custom) setting success");
2920                         }
2921                 }
2922
2923                 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2924                         && (player->set_mode.rich_audio)) {
2925                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2926                 }
2927         }
2928
2929         /* create audio sink */
2930         LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2931                         player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2932                         player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2933
2934         /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2935         if (player->is_360_feature_enabled &&
2936                 player->is_content_spherical &&
2937                 channels == 4 &&
2938                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2939                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2940                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2941
2942                 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2943
2944                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2945
2946                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2947                 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2948                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2949                 gst_caps_unref(acaps);
2950
2951                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2952
2953                 player->is_openal_plugin_used = TRUE;
2954         } else {
2955                 if (player->is_360_feature_enabled && player->is_content_spherical)
2956                         LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2957                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2958         }
2959
2960         if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2961                 (player->videodec_linked && player->ini.use_system_clock)) {
2962                 LOGD("system clock will be used.");
2963                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
2964         }
2965
2966         if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2967                 __mmplayer_gst_set_pulsesink_property(player);
2968         } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2969                 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2970                         goto ERROR;
2971         }
2972
2973         /* qos on */
2974         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
2975         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2976
2977         sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2978         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2979                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2980         gst_object_unref(GST_OBJECT(sink_pad));
2981
2982         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2983
2984         MMPLAYER_FLEAVE();
2985         return MM_ERROR_NONE;
2986
2987 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2988         MMPLAYER_FLEAVE();
2989         return MM_ERROR_PLAYER_INTERNAL;
2990 }
2991
2992 static int
2993 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2994 {
2995         mmplayer_gst_element_t *audiobin = NULL;
2996         enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2997
2998         gchar *dst_format = NULL;
2999         int dst_len = 0;
3000         int dst_samplerate = 0;
3001         int dst_channels = 0;
3002         GstCaps *caps = NULL;
3003         char *caps_str = NULL;
3004
3005         MMPLAYER_FENTER();
3006         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3007                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3008
3009         audiobin = player->pipeline->audiobin;
3010
3011         LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
3012
3013         /* audio bin structure according to the mmplayer_audio_extract_opt_e.
3014
3015            [case 1] extract interleave audio pcm without playback
3016                                 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
3017                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
3018
3019                                 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
3020
3021            [case 2] deinterleave for each channel without playback
3022                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
3023                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
3024
3025                                 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
3026                                                                                                                                                    - fakesink (sync or not)
3027                                                                                                                                                    - ...      (sync or not)
3028
3029            [case 3] [case 1(sync only)] + playback
3030                                 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3031
3032                                 * src - ... - tee - queue1 - playback path
3033                                                                   - queue2 - [case1 pipeline with sync]
3034
3035            [case 4] [case 2(sync only)] + playback
3036                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3037
3038                                 * src - ... - tee - queue1 - playback path
3039                                                                   - queue2 - [case2 pipeline with sync]
3040
3041          */
3042
3043         /* 1. create tee and playback path
3044               'tee' should be added at first to copy the decoded stream
3045          */
3046         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3047                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3048                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3049
3050                 /* tee - path 1 : for playback path */
3051                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3052                 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3053
3054                 /* tee - path 2 : for extract path */
3055                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3056                 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3057         }
3058
3059         /* if there is tee, 'tee - path 2' is linked here */
3060         /* converter */
3061         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3062
3063         /* resampler */
3064         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER,  player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3065
3066         /* 2. decide the extract pcm format */
3067         mm_attrs_multiple_get(player->attrs, NULL,
3068                                 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3069                                 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3070                                 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3071                                 NULL);
3072
3073         LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3074                         dst_format, dst_len, dst_samplerate, dst_channels);
3075
3076         if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3077                 mm_attrs_multiple_get(player->attrs, NULL,
3078                                         "content_audio_format", &dst_format, &dst_len, /* get string and len */
3079                                         "content_audio_samplerate", &dst_samplerate,
3080                                         "content_audio_channels", &dst_channels,
3081                                         NULL);
3082
3083                 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3084                                 dst_format, dst_len, dst_samplerate, dst_channels);
3085
3086                 /* If there is no enough information, set it to platform default value. */
3087                 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3088                         LOGD("set platform default format");
3089                         dst_format = DEFAULT_PCM_OUT_FORMAT;
3090                 }
3091                 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3092                 if (dst_channels <= 0)   dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3093         }
3094
3095         /* 3. create capsfilter */
3096         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3097         caps = gst_caps_new_simple("audio/x-raw",
3098                         "format", G_TYPE_STRING, dst_format,
3099                         "rate", G_TYPE_INT, dst_samplerate,
3100                         "channels", G_TYPE_INT, dst_channels,
3101                         NULL);
3102
3103         caps_str = gst_caps_to_string(caps);
3104         LOGD("new caps : %s", caps_str);
3105
3106         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3107
3108         /* clean */
3109         gst_caps_unref(caps);
3110         MMPLAYER_FREEIF(caps_str);
3111
3112         /* 4-1. create deinterleave to extract pcm for each channel */
3113         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3114                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3115                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3116
3117                 /* audiosink will be added after getting signal for each channel */
3118                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3119                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3120                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3121                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3122                 player->no_more_pad = FALSE;
3123         } else {
3124         /* 4-2. create fakesink to extract interleaved pcm */
3125                 LOGD("add audio fakesink for interleaved audio");
3126                 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3127                 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3128                         g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3129                 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3130
3131                 _mmplayer_add_signal_connection(player,
3132                         G_OBJECT(audiobin[extract_sink_id].gst),
3133                         MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3134                         "handoff",
3135                         G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3136                         (gpointer)player);
3137
3138                 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3139         }
3140
3141         MMPLAYER_FLEAVE();
3142         return MM_ERROR_NONE;
3143
3144 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3145         MMPLAYER_FLEAVE();
3146         return MM_ERROR_PLAYER_INTERNAL;
3147 }
3148
3149 static int
3150 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3151 {
3152         int ret = MM_ERROR_NONE;
3153         mmplayer_gst_element_t *audiobin = NULL;
3154         GList *element_bucket = NULL;
3155
3156         MMPLAYER_FENTER();
3157         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3158                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3159
3160         audiobin = player->pipeline->audiobin;
3161
3162         if (player->build_audio_offload) { /* skip all the audio filters */
3163                 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3164
3165                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3166                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3167                                 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3168
3169                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3170                 goto DONE;
3171         }
3172
3173         /* FIXME: need to mention the supportable condition at API reference */
3174         if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3175                 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3176         else
3177                 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3178
3179         if (ret != MM_ERROR_NONE)
3180                 goto ERROR;
3181 DONE:
3182         LOGD("success to make audio bin element");
3183         *bucket = element_bucket;
3184
3185         MMPLAYER_FLEAVE();
3186         return MM_ERROR_NONE;
3187
3188 ERROR:
3189         LOGE("failed to make audio bin element");
3190         g_list_free(element_bucket);
3191
3192         *bucket = NULL;
3193         MMPLAYER_FLEAVE();
3194         return MM_ERROR_PLAYER_INTERNAL;
3195 }
3196
3197 static int
3198 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3199 {
3200         mmplayer_gst_element_t *first_element = NULL;
3201         mmplayer_gst_element_t *audiobin = NULL;
3202         GstPad *pad = NULL;
3203         GstPad *ghostpad = NULL;
3204         GList *element_bucket = NULL;
3205         int i = 0;
3206
3207         MMPLAYER_FENTER();
3208         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3209
3210         /* alloc handles */
3211         audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3212         if (!audiobin) {
3213                 LOGE("failed to allocate memory for audiobin");
3214                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3215         }
3216
3217         /* create bin */
3218         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3219         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3220         if (!audiobin[MMPLAYER_A_BIN].gst) {
3221                 LOGE("failed to create audiobin");
3222                 goto ERROR;
3223         }
3224
3225         /* take it */
3226         player->pipeline->audiobin = audiobin;
3227
3228         /* create audio filters and audiosink */
3229         if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3230                 goto ERROR;
3231
3232         /* adding created elements to bin */
3233         LOGD("adding created elements to bin");
3234         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3235                 goto ERROR;
3236
3237         /* linking elements in the bucket by added order. */
3238         LOGD("Linking elements in the bucket by added order.");
3239         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3240                 goto ERROR;
3241
3242         /* get first element's sinkpad for creating ghostpad */
3243         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3244         if (!first_element) {
3245                 LOGE("failed to get first elem");
3246                 goto ERROR;
3247         }
3248
3249         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3250         if (!pad) {
3251                 LOGE("failed to get pad from first element of audiobin");
3252                 goto ERROR;
3253         }
3254
3255         ghostpad = gst_ghost_pad_new("sink", pad);
3256         if (!ghostpad) {
3257                 LOGE("failed to create ghostpad");
3258                 goto ERROR;
3259         }
3260
3261         if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3262                 LOGE("failed to add ghostpad to audiobin");
3263                 goto ERROR;
3264         }
3265
3266         gst_object_unref(pad);
3267
3268         g_list_free(element_bucket);
3269         MMPLAYER_FLEAVE();
3270
3271         return MM_ERROR_NONE;
3272
3273 ERROR:
3274         LOGD("ERROR : releasing audiobin");
3275
3276         if (pad)
3277                 gst_object_unref(GST_OBJECT(pad));
3278
3279         if (ghostpad)
3280                 gst_object_unref(GST_OBJECT(ghostpad));
3281
3282         if (element_bucket)
3283                 g_list_free(element_bucket);
3284
3285         /* release element which are not added to bin */
3286         for (i = 1; i < MMPLAYER_A_NUM; i++) {
3287                 /* NOTE : skip bin */
3288                 if (audiobin[i].gst) {
3289                         GstObject *parent = NULL;
3290                         parent = gst_element_get_parent(audiobin[i].gst);
3291
3292                         if (!parent) {
3293                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3294                                 audiobin[i].gst = NULL;
3295                         } else
3296                                 gst_object_unref(GST_OBJECT(parent));
3297                 }
3298         }
3299
3300         /* release audiobin with it's children */
3301         if (audiobin[MMPLAYER_A_BIN].gst)
3302                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3303
3304         MMPLAYER_FREEIF(audiobin);
3305
3306         player->pipeline->audiobin = NULL;
3307
3308         return MM_ERROR_PLAYER_INTERNAL;
3309 }
3310
3311 static guint32
3312 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3313 {
3314         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3315 }
3316
3317 int
3318 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3319 {
3320         int ret = MM_ERROR_NONE;
3321         GList *l = NULL;
3322         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3323         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3324
3325         MMPLAYER_VIDEO_BO_LOCK(player);
3326
3327         if (player->video_bo_list) {
3328                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3329                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3330                         if (tmp && tmp->bo == bo) {
3331                                 tmp->used = FALSE;
3332                                 LOGD("release bo %p", bo);
3333                                 tbm_bo_unref(tmp->bo);
3334                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3335                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
3336                                 return ret;
3337                         }
3338                 }
3339         } else {
3340                 /* hw codec is running or the list was reset for DRC. */
3341                 LOGW("there is no bo list.");
3342         }
3343         MMPLAYER_VIDEO_BO_UNLOCK(player);
3344
3345         LOGW("failed to find bo %p", bo);
3346         return ret;
3347 }
3348 static void
3349 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3350 {
3351         if (!tmp)
3352                 return;
3353
3354         if (tmp->bo)
3355                 tbm_bo_unref(tmp->bo);
3356         g_free(tmp);
3357 }
3358
3359 static void
3360 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3361 {
3362         MMPLAYER_FENTER();
3363         MMPLAYER_RETURN_IF_FAIL(player);
3364
3365         MMPLAYER_VIDEO_BO_LOCK(player);
3366         if (player->video_bo_list) {
3367                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3368                 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3369                 player->video_bo_list = NULL;
3370         }
3371         player->video_bo_size = 0;
3372         MMPLAYER_VIDEO_BO_UNLOCK(player);
3373
3374         MMPLAYER_FLEAVE();
3375         return;
3376 }
3377
3378 static void *
3379 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3380 {
3381         GList *l = NULL;
3382         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3383         gboolean ret = TRUE;
3384         gint64 end_time = 0;
3385
3386         /* check DRC, if it is, destroy the prev bo list to create again */
3387         if (player->video_bo_size != size) {
3388                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3389                 __mmplayer_video_stream_destroy_bo_list(player);
3390                 player->video_bo_size = size;
3391         }
3392
3393         MMPLAYER_VIDEO_BO_LOCK(player);
3394
3395         if ((!player->video_bo_list) ||
3396                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3397
3398                 /* create bo list */
3399                 int idx = 0;
3400                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3401
3402                 if (player->video_bo_list) {
3403                         /* if bo list did not created all, try it again. */
3404                         idx = g_list_length(player->video_bo_list);
3405                         LOGD("bo list exist(len: %d)", idx);
3406                 }
3407
3408                 for (; idx < player->ini.num_of_video_bo; idx++) {
3409                         mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3410                         if (!bo_info) {
3411                                 LOGE("Fail to alloc bo_info.");
3412                                 break;
3413                         }
3414                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3415                         if (!bo_info->bo) {
3416                                 LOGE("Fail to tbm_bo_alloc.");
3417                                 MMPLAYER_FREEIF(bo_info);
3418                                 break;
3419                         }
3420                         bo_info->used = FALSE;
3421                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3422                 }
3423
3424                 /* update video num buffers */
3425                 LOGD("video_num_buffers : %d", idx);
3426                 mm_player_set_attribute((MMHandleType)player, NULL,
3427                                 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3428                                 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3429                                 NULL);
3430
3431                 if (idx == 0) {
3432                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3433                         return NULL;
3434                 }
3435         }
3436
3437         if (player->ini.video_bo_timeout > 0)
3438                 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3439
3440         while (TRUE) {
3441                 /* get bo from list*/
3442                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3443                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3444                         if (tmp && (tmp->used == FALSE)) {
3445                                 LOGD("found bo %p to use", tmp->bo);
3446                                 tmp->used = TRUE;
3447                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3448                                 return tbm_bo_ref(tmp->bo);
3449                         }
3450                 }
3451
3452                 if (player->ini.video_bo_timeout <= 0) {
3453                         MMPLAYER_VIDEO_BO_WAIT(player);
3454                 } else {
3455                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3456                         if (!ret) {
3457                                 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3458                                 break;
3459                         }
3460                 }
3461         }
3462
3463         MMPLAYER_VIDEO_BO_UNLOCK(player);
3464         return NULL;
3465 }
3466
3467 static void
3468 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3469 {
3470         mmplayer_t *player = (mmplayer_t *)data;
3471         MMPLAYER_FENTER();
3472         MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3473
3474         /* send prerolled pkt */
3475         player->video_stream_prerolled = false;
3476
3477         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3478
3479         /* not to send prerolled pkt again */
3480         player->video_stream_prerolled = true;
3481 }
3482
3483 static void
3484 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3485 {
3486         mmplayer_t *player = (mmplayer_t *)data;
3487         mmplayer_video_decoded_data_info_t *stream = NULL;
3488         GstMemory *mem = NULL;
3489
3490         MMPLAYER_FENTER();
3491         MMPLAYER_RETURN_IF_FAIL(player);
3492         MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3493
3494         if (player->video_stream_prerolled) {
3495                 player->video_stream_prerolled = false;
3496                 LOGD("skip the prerolled pkt not to send it again");
3497                 return;
3498         }
3499
3500         /* clear stream data structure */
3501         stream = __mmplayer_create_stream_from_pad(pad);
3502         if (!stream) {
3503                 LOGE("failed to alloc stream");
3504                 return;
3505         }
3506
3507         _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3508
3509         /* set size and timestamp */
3510         mem = gst_buffer_peek_memory(buffer, 0);
3511         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3512         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3513
3514         /* check zero-copy */
3515         if (player->set_mode.video_zc &&
3516                 player->set_mode.video_export &&
3517                 gst_is_tizen_memory(mem)) {
3518                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3519                 stream->internal_buffer = gst_buffer_ref(buffer);
3520         } else { /* sw codec */
3521                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3522                         goto ERROR;
3523
3524                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3525                         goto ERROR;
3526         }
3527
3528         if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3529                 LOGE("failed to send video decoded data.");
3530                 goto ERROR;
3531         }
3532
3533         return;
3534
3535 ERROR:
3536         LOGE("release video stream resource.");
3537         if (gst_is_tizen_memory(mem)) {
3538                 int i = 0;
3539                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3540                         if (stream->bo[i])
3541                                 tbm_bo_unref(stream->bo[i]);
3542                 }
3543
3544                 /* unref gst buffer */
3545                 if (stream->internal_buffer)
3546                         gst_buffer_unref(stream->internal_buffer);
3547         } else {
3548                 if (stream->bo[0])
3549                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3550         }
3551         MMPLAYER_FREEIF(stream);
3552         return;
3553 }
3554
3555 static void
3556 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3557 {
3558         mmplayer_gst_element_t *videobin = NULL;
3559
3560         MMPLAYER_FENTER();
3561         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3562
3563         videobin = player->pipeline->videobin;
3564
3565         /* Set spatial media metadata and/or user settings to the element.
3566          * */
3567         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3568                         "projection-type", player->video360_metadata.projection_type, NULL);
3569
3570         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3571                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3572
3573         if (player->video360_metadata.full_pano_width_pixels &&
3574                         player->video360_metadata.full_pano_height_pixels &&
3575                         player->video360_metadata.cropped_area_image_width &&
3576                         player->video360_metadata.cropped_area_image_height) {
3577                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3578                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3579                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3580                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3581                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3582                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3583                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3584                                 NULL);
3585         }
3586
3587         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3588                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3589                                 "horizontal-fov", player->video360_horizontal_fov,
3590                                 "vertical-fov", player->video360_vertical_fov, NULL);
3591         }
3592
3593         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3594                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3595                                 "zoom", 1.0f / player->video360_zoom, NULL);
3596         }
3597
3598         if (player->video360_yaw_radians <= M_PI &&
3599                         player->video360_yaw_radians >= -M_PI &&
3600                         player->video360_pitch_radians <= M_PI_2 &&
3601                         player->video360_pitch_radians >= -M_PI_2) {
3602                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3603                                 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3604                                 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3605         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3606                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3607                                 "pose-yaw", player->video360_metadata.init_view_heading,
3608                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3609         }
3610
3611         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3612                         "passthrough", !player->is_video360_enabled, NULL);
3613
3614
3615         MMPLAYER_FLEAVE();
3616 }
3617
3618 static int
3619 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3620 {
3621         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3622         GList *element_bucket = NULL;
3623
3624         MMPLAYER_FENTER();
3625         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3626
3627         /* create video360 filter */
3628         if (player->is_360_feature_enabled && player->is_content_spherical) {
3629                 LOGD("create video360 element");
3630                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3631                 __mmplayer_gst_set_video360_property(player);
3632                 goto EXIT;
3633         }
3634
3635         if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3636                 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3637                 player->set_mode.video_zc) {
3638                 LOGD("skip creating the videoconv and rotator");
3639                 return MM_ERROR_NONE;
3640         }
3641
3642         /* in case of sw codec & overlay surface type, except 360 playback.
3643          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3644         LOGD("create video converter: %s", video_csc);
3645         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3646
3647 EXIT:
3648         *bucket = element_bucket;
3649         MMPLAYER_FLEAVE();
3650         return MM_ERROR_NONE;
3651
3652 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3653         g_list_free(element_bucket);
3654
3655         *bucket = NULL;
3656         MMPLAYER_FLEAVE();
3657         return MM_ERROR_PLAYER_INTERNAL;
3658 }
3659
3660 static gchar *
3661 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3662 {
3663         gchar *factory_name = NULL;
3664
3665         switch (surface_type) {
3666         case MM_DISPLAY_SURFACE_OVERLAY:
3667         /* fall through */
3668         case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3669                 if (strlen(player->ini.videosink_element_overlay) > 0)
3670                         factory_name = player->ini.videosink_element_overlay;
3671                 break;
3672         case MM_DISPLAY_SURFACE_REMOTE:
3673         /* fall through */
3674         case MM_DISPLAY_SURFACE_NULL:
3675                 if (strlen(player->ini.videosink_element_fake) > 0)
3676                         factory_name = player->ini.videosink_element_fake;
3677                 break;
3678         default:
3679                 LOGE("unidentified surface type");
3680                 break;
3681         }
3682
3683         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3684         return factory_name;
3685 }
3686
3687 static int
3688 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3689 {
3690         gchar *factory_name = NULL;
3691         mmplayer_gst_element_t *videobin = NULL;
3692         MMHandleType attrs;
3693         int gapless = 0;
3694
3695         MMPLAYER_FENTER();
3696         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3697
3698         videobin = player->pipeline->videobin;
3699         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3700
3701         attrs = MMPLAYER_GET_ATTRS(player);
3702         if (!attrs) {
3703                 LOGE("cannot get content attribute");
3704                 return MM_ERROR_PLAYER_INTERNAL;
3705         }
3706
3707         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3708                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3709                 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3710                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3711                                 "use-tbm", use_tbm, NULL);
3712                 }
3713
3714                 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3715                         return MM_ERROR_PLAYER_INTERNAL;
3716
3717                 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3718
3719         } else {
3720                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3721                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3722         }
3723
3724         mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3725         if (gapless > 0) {
3726                 LOGD("disable last-sample");
3727                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3728         }
3729
3730         if (player->set_mode.video_export) {
3731                 int enable = 0;
3732                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3733                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3734                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3735
3736                 _mmplayer_add_signal_connection(player,
3737                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3738                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3739                                                                 "handoff",
3740                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3741                                                                 (gpointer)player);
3742
3743                 _mmplayer_add_signal_connection(player,
3744                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3745                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3746                                                                 "preroll-handoff",
3747                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3748                                                                 (gpointer)player);
3749         }
3750
3751         if (videobin[MMPLAYER_V_SINK].gst) {
3752                 GstPad *sink_pad = NULL;
3753                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3754                 if (sink_pad) {
3755                         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3756                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3757                         gst_object_unref(GST_OBJECT(sink_pad));
3758                 } else {
3759                         LOGE("failed to get sink pad from videosink");
3760                 }
3761         }
3762
3763         return MM_ERROR_NONE;
3764 }
3765
3766 /**
3767  * VIDEO BIN
3768  * - video overlay surface(arm/x86) : tizenwlsink
3769  */
3770 static int
3771 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3772 {
3773         GstPad *pad = NULL;
3774         GList *element_bucket = NULL;
3775         mmplayer_gst_element_t *first_element = NULL;
3776         mmplayer_gst_element_t *videobin = NULL;
3777         gchar *videosink_factory_name = NULL;
3778
3779         MMPLAYER_FENTER();
3780         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3781
3782         /* alloc handles */
3783         videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3784         if (!videobin)
3785                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3786
3787         player->pipeline->videobin = videobin;
3788
3789         /* create bin */
3790         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3791         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3792         if (!videobin[MMPLAYER_V_BIN].gst) {
3793                 LOGE("failed to create videobin");
3794                 goto ERROR;
3795         }
3796
3797         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3798                 goto ERROR;
3799
3800         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3801         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3802
3803         /* additional setting for sink plug-in */
3804         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3805                 LOGE("failed to set video property");
3806                 goto ERROR;
3807         }
3808
3809         /* store it as it's sink element */
3810         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3811
3812         /* adding created elements to bin */
3813         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3814                 LOGE("failed to add elements");
3815                 goto ERROR;
3816         }
3817
3818         /* Linking elements in the bucket by added order */
3819         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3820                 LOGE("failed to link elements");
3821                 goto ERROR;
3822         }
3823
3824         /* get first element's sinkpad for creating ghostpad */
3825         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3826         if (!first_element) {
3827                 LOGE("failed to get first element from bucket");
3828                 goto ERROR;
3829         }
3830
3831         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3832         if (!pad) {
3833                 LOGE("failed to get pad from first element");
3834                 goto ERROR;
3835         }
3836
3837         /* create ghostpad */
3838         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3839         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3840                 LOGE("failed to add ghostpad to videobin");
3841                 goto ERROR;
3842         }
3843         gst_object_unref(pad);
3844
3845         /* done. free allocated variables */
3846         g_list_free(element_bucket);
3847
3848         MMPLAYER_FLEAVE();
3849
3850         return MM_ERROR_NONE;
3851
3852 ERROR:
3853         LOGE("ERROR : releasing videobin");
3854         g_list_free(element_bucket);
3855
3856         if (pad)
3857                 gst_object_unref(GST_OBJECT(pad));
3858
3859         /* release videobin with it's children */
3860         if (videobin[MMPLAYER_V_BIN].gst)
3861                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3862
3863         MMPLAYER_FREEIF(videobin);
3864         player->pipeline->videobin = NULL;
3865
3866         return MM_ERROR_PLAYER_INTERNAL;
3867 }
3868
3869 static int
3870 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3871 {
3872         GList *element_bucket = NULL;
3873         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3874
3875         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3876         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3877         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3878                                                         "signal-handoffs", FALSE,
3879                                                         NULL);
3880
3881         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3882         _mmplayer_add_signal_connection(player,
3883                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3884                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3885                                                         "handoff",
3886                                                         G_CALLBACK(__mmplayer_update_subtitle),
3887                                                         (gpointer)player);
3888
3889         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3890                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3891
3892         if (!player->play_subtitle) {
3893                 LOGD("add textbin sink as sink element of whole pipeline.");
3894                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3895         }
3896
3897         /* adding created elements to bin */
3898         LOGD("adding created elements to bin");
3899         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3900                 LOGE("failed to add elements");
3901                 goto ERROR;
3902         }
3903
3904         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3905         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3906         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3907
3908         /* linking elements in the bucket by added order. */
3909         LOGD("Linking elements in the bucket by added order.");
3910         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3911                 LOGE("failed to link elements");
3912                 goto ERROR;
3913         }
3914
3915         if (textbin[MMPLAYER_T_QUEUE].gst) {
3916                 GstPad *pad = NULL;
3917                 GstPad *ghostpad = NULL;
3918
3919                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3920                 if (!pad) {
3921                         LOGE("failed to get sink pad of text queue");
3922                         goto ERROR;
3923                 }
3924
3925                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3926                 gst_object_unref(pad);
3927
3928                 if (!ghostpad) {
3929                         LOGE("failed to create ghostpad of textbin");
3930                         goto ERROR;
3931                 }
3932
3933                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3934                         LOGE("failed to add ghostpad to textbin");
3935                         gst_object_unref(ghostpad);
3936                         goto ERROR;
3937                 }
3938         }
3939
3940         g_list_free(element_bucket);
3941
3942         return MM_ERROR_NONE;
3943
3944 ERROR:
3945
3946         g_list_free(element_bucket);
3947
3948         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3949                 LOGE("remove textbin sink from sink list");
3950                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3951         }
3952
3953         /* release element at __mmplayer_gst_create_text_sink_bin */
3954         return MM_ERROR_PLAYER_INTERNAL;
3955 }
3956
3957 static int
3958 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3959 {
3960         mmplayer_gst_element_t *textbin = NULL;
3961         int surface_type = 0;
3962         gint i = 0;
3963
3964         MMPLAYER_FENTER();
3965
3966         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3967
3968         /* alloc handles */
3969         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3970         if (!textbin) {
3971                 LOGE("failed to allocate memory for textbin");
3972                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3973         }
3974
3975         /* create bin */
3976         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3977         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3978         if (!textbin[MMPLAYER_T_BIN].gst) {
3979                 LOGE("failed to create textbin");
3980                 goto ERROR;
3981         }
3982
3983         /* take it */
3984         player->pipeline->textbin = textbin;
3985
3986         /* fakesink */
3987         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3988         LOGD("surface type for subtitle : %d", surface_type);
3989         switch (surface_type) {
3990         case MM_DISPLAY_SURFACE_OVERLAY:
3991         case MM_DISPLAY_SURFACE_NULL:
3992         case MM_DISPLAY_SURFACE_REMOTE:
3993                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3994                         LOGE("failed to make plain text elements");
3995                         goto ERROR;
3996                 }
3997                 break;
3998         default:
3999                 goto ERROR;
4000                 break;
4001         }
4002
4003         MMPLAYER_FLEAVE();
4004
4005         return MM_ERROR_NONE;
4006
4007 ERROR:
4008
4009         LOGD("ERROR : releasing textbin");
4010
4011         /* release signal */
4012         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4013
4014         /* release element which are not added to bin */
4015         for (i = 1; i < MMPLAYER_T_NUM; i++) {
4016                 /* NOTE : skip bin */
4017                 if (textbin[i].gst) {
4018                         GstObject *parent = NULL;
4019                         parent = gst_element_get_parent(textbin[i].gst);
4020
4021                         if (!parent) {
4022                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
4023                                 textbin[i].gst = NULL;
4024                         } else {
4025                                 gst_object_unref(GST_OBJECT(parent));
4026                         }
4027                 }
4028         }
4029
4030         /* release textbin with it's children */
4031         if (textbin[MMPLAYER_T_BIN].gst)
4032                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4033
4034         MMPLAYER_FREEIF(textbin);
4035         player->pipeline->textbin = NULL;
4036
4037         MMPLAYER_FLEAVE();
4038         return MM_ERROR_PLAYER_INTERNAL;
4039 }
4040
4041 static int
4042 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4043 {
4044         mmplayer_gst_element_t *mainbin = NULL;
4045         mmplayer_gst_element_t *textbin = NULL;
4046         MMHandleType attrs = 0;
4047         GstElement *subsrc = NULL;
4048         GstElement *subparse = NULL;
4049         gchar *subtitle_uri = NULL;
4050         const gchar *charset = NULL;
4051         GstPad *pad = NULL;
4052
4053         MMPLAYER_FENTER();
4054
4055         /* get mainbin */
4056         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4057                                                                 player->pipeline &&
4058                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4059
4060         mainbin = player->pipeline->mainbin;
4061
4062         attrs = MMPLAYER_GET_ATTRS(player);
4063         if (!attrs) {
4064                 LOGE("cannot get content attribute");
4065                 return MM_ERROR_PLAYER_INTERNAL;
4066         }
4067
4068         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4069         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4070                 LOGE("subtitle uri is not proper filepath.");
4071                 return MM_ERROR_PLAYER_INVALID_URI;
4072         }
4073
4074         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4075                 LOGE("failed to get storage info of subtitle path");
4076                 return MM_ERROR_PLAYER_INVALID_URI;
4077         }
4078
4079         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4080
4081         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4082         player->subtitle_language_list = NULL;
4083         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4084
4085         /* create the subtitle source */
4086         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4087         if (!subsrc) {
4088                 LOGE("failed to create filesrc element");
4089                 goto ERROR;
4090         }
4091         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4092
4093         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4094         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4095
4096         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4097                 LOGW("failed to add queue");
4098                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4099                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4100                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4101                 goto ERROR;
4102         }
4103
4104         /* subparse */
4105         subparse = gst_element_factory_make("subparse", "subtitle_parser");
4106         if (!subparse) {
4107                 LOGE("failed to create subparse element");
4108                 goto ERROR;
4109         }
4110
4111         charset = _mmplayer_get_charset(subtitle_uri);
4112         if (charset) {
4113                 LOGD("detected charset is %s", charset);
4114                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4115         }
4116
4117         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4118         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4119
4120         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4121                 LOGW("failed to add subparse");
4122                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4123                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4124                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4125                 goto ERROR;
4126         }
4127
4128         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4129                 LOGW("failed to link subsrc and subparse");
4130                 goto ERROR;
4131         }
4132
4133         player->play_subtitle = TRUE;
4134         player->adjust_subtitle_pos = 0;
4135
4136         LOGD("play subtitle using subtitle file");
4137
4138         if (player->pipeline->textbin == NULL) {
4139                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4140                         LOGE("failed to create text sink bin. continuing without text");
4141                         goto ERROR;
4142                 }
4143
4144                 textbin = player->pipeline->textbin;
4145
4146                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4147                         LOGW("failed to add textbin");
4148
4149                         /* release signal */
4150                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4151
4152                         /* release textbin with it's children */
4153                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4154                         MMPLAYER_FREEIF(player->pipeline->textbin);
4155                         player->pipeline->textbin = textbin = NULL;
4156                         goto ERROR;
4157                 }
4158
4159                 LOGD("link text input selector and textbin ghost pad");
4160
4161                 player->textsink_linked = 1;
4162                 player->external_text_idx = 0;
4163                 LOGI("textsink is linked");
4164         } else {
4165                 textbin = player->pipeline->textbin;
4166                 LOGD("text bin has been created. reuse it.");
4167                 player->external_text_idx = 1;
4168         }
4169
4170         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4171                 LOGW("failed to link subparse and textbin");
4172                 goto ERROR;
4173         }
4174
4175         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4176         if (!pad) {
4177                 LOGE("failed to get sink pad from textsink to probe data");
4178                 goto ERROR;
4179         }
4180
4181         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4182                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4183
4184         gst_object_unref(pad);
4185         pad = NULL;
4186
4187         /* create dot. for debugging */
4188         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4189         MMPLAYER_FLEAVE();
4190
4191         return MM_ERROR_NONE;
4192
4193 ERROR:
4194         /* release text pipeline resource */
4195         player->textsink_linked = 0;
4196
4197         /* release signal */
4198         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4199
4200         if (player->pipeline->textbin) {
4201                 LOGE("remove textbin");
4202
4203                 /* release textbin with it's children */
4204                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4205                 MMPLAYER_FREEIF(player->pipeline->textbin);
4206                 player->pipeline->textbin = NULL;
4207
4208         }
4209
4210         /* release subtitle elem */
4211         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4212         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4213
4214         return MM_ERROR_PLAYER_INTERNAL;
4215 }
4216
4217 gboolean
4218 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4219 {
4220         mmplayer_t *player = (mmplayer_t *)data;
4221         MMMessageParamType msg = {0, };
4222         GstClockTime duration = 0;
4223         gpointer text = NULL;
4224         guint text_size = 0;
4225         gboolean ret = TRUE;
4226         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4227
4228         MMPLAYER_FENTER();
4229
4230         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4231         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4232
4233         if (player->is_subtitle_force_drop) {
4234                 LOGW("subtitle is dropped forcedly.");
4235                 return ret;
4236         }
4237
4238         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4239         text = mapinfo.data;
4240         text_size = mapinfo.size;
4241
4242         if (player->set_mode.subtitle_off) {
4243                 LOGD("subtitle is OFF.");
4244                 return TRUE;
4245         }
4246
4247         if (!text || (text_size == 0)) {
4248                 LOGD("There is no subtitle to be displayed.");
4249                 return TRUE;
4250         }
4251
4252         msg.data = (void *)text;
4253
4254         duration = GST_BUFFER_DURATION(buffer);
4255
4256         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4257                 if (player->duration > GST_BUFFER_PTS(buffer))
4258                         duration = player->duration - GST_BUFFER_PTS(buffer);
4259                 else
4260                         duration = 0;
4261                 LOGI("subtitle duration is invalid, subtitle duration change "
4262                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4263         }
4264         msg.subtitle.duration = (unsigned long)GST_TIME_AS_MSECONDS(duration);
4265
4266         LOGD("update subtitle : [%lu msec] %s", msg.subtitle.duration, (char *)msg.data);
4267
4268         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4269         gst_buffer_unmap(buffer, &mapinfo);
4270
4271         MMPLAYER_FLEAVE();
4272
4273         return ret;
4274 }
4275
4276 static GstPadProbeReturn
4277 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4278 {
4279         mmplayer_t *player = (mmplayer_t *)u_data;
4280         GstClockTime cur_timestamp = 0;
4281         gint64 adjusted_timestamp = 0;
4282         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4283
4284         MMPLAYER_RETURN_VAL_IF_FAIL(player, GST_PAD_PROBE_DROP);
4285
4286         if (player->set_mode.subtitle_off)
4287                 return GST_PAD_PROBE_OK;
4288
4289         if (player->adjust_subtitle_pos == 0)
4290                 return GST_PAD_PROBE_OK;
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 GST_PAD_PROBE_DROP;
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)) {
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)) {
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                                         if (caps)
7837                                                 gst_caps_unref(caps);
7838                                         gst_object_unref(GST_OBJECT(srcpad));
7839                                 }
7840                         }
7841                 }
7842         } else if (g_strrstr(klass, "Demuxer")) {
7843                 if (g_strrstr(klass, "Adaptive")) {
7844                         player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7845                         player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7846
7847                         MMPLAYER_FREEIF(player->type_caps_str);
7848
7849                         if (g_strrstr(factory_name, "hlsdemux")) {
7850                                 player->type_caps_str = g_strdup("application/x-hls");
7851                                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7852                         } else if (g_strrstr(factory_name, "dashdemux")) {
7853                                 player->type_caps_str = g_strdup("application/dash+xml");
7854                                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7855                         } else {
7856                                 LOGE("not supported type");
7857                                 return;
7858                         }
7859                         player->streamer->is_adaptive_streaming = TRUE;
7860
7861                         if (player->streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
7862                                 player->streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
7863
7864                         LOGD("max variant limit: %d, %d, %d, prebuffer time: %d ms",
7865                                 player->adaptive_info.limit.bandwidth,
7866                                 player->adaptive_info.limit.width,
7867                                 player->adaptive_info.limit.height,
7868                                 player->streamer->buffering_req.prebuffer_time);
7869
7870                         g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7871                                 "max-bitrate", player->adaptive_info.limit.bandwidth,
7872                                 "max-video-width", player->adaptive_info.limit.width,
7873                                 "max-video-height", player->adaptive_info.limit.height,
7874                                 "low-watermark-time", (guint64)(player->streamer->buffering_req.prebuffer_time * GST_MSECOND),
7875                                 NULL);
7876                 } else {
7877 #ifdef __DEBUG__
7878                         LOGD("plugged element is demuxer. take it");
7879 #endif
7880                         player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7881                         player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7882                 }
7883         } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7884                 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7885                 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7886         }
7887
7888         if (g_strrstr(factory_name, "mpegaudioparse")) {
7889                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7890                         (__mmplayer_is_only_mp3_type(player->type_caps_str))) {
7891                         LOGD("[mpegaudioparse] set streaming pull mode.");
7892                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7893                 }
7894         } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7895                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7896
7897                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7898
7899                 /* set mq unlinked cache size to avoid not-linked error */
7900                 gboolean sync_by_running_time = FALSE;
7901                 g_object_get(G_OBJECT(element), "sync-by-running-time", &sync_by_running_time, NULL);
7902                 if (sync_by_running_time)
7903                         g_object_set(G_OBJECT(element), "unlinked-cache-time", MQ_UNLINKED_CACHE_TIME, NULL);
7904
7905                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7906                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7907
7908                 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7909                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7910                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7911                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7912                 }
7913         }
7914
7915         return;
7916 }
7917
7918 static void
7919 __mmplayer_release_misc(mmplayer_t *player)
7920 {
7921         int i;
7922         bool cur_mode = player->set_mode.rich_audio;
7923         MMPLAYER_FENTER();
7924
7925         MMPLAYER_RETURN_IF_FAIL(player);
7926
7927         player->sent_bos = FALSE;
7928         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7929
7930         player->seek_state = MMPLAYER_SEEK_NONE;
7931
7932         player->total_bitrate = 0;
7933         player->total_maximum_bitrate = 0;
7934
7935         player->not_found_demuxer = 0;
7936
7937         player->last_position = 0;
7938         player->duration = 0;
7939         player->http_content_size = 0;
7940         player->not_supported_codec = MISSING_PLUGIN_NONE;
7941         player->can_support_codec = FOUND_PLUGIN_NONE;
7942         player->pending_seek.is_pending = false;
7943         player->pending_seek.pos = 0;
7944         player->msg_posted = FALSE;
7945         player->has_many_types = FALSE;
7946         player->is_subtitle_force_drop = FALSE;
7947         player->play_subtitle = FALSE;
7948         player->adjust_subtitle_pos = 0;
7949         player->has_closed_caption = FALSE;
7950         player->set_mode.video_export = false;
7951         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7952         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7953         /* recover mode */
7954         player->set_mode.rich_audio = cur_mode;
7955
7956         if (player->audio_device_cb_id > 0 &&
7957                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7958                 LOGW("failed to remove audio device_connected_callback");
7959         player->audio_device_cb_id = 0;
7960
7961         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7962                 player->bitrate[i] = 0;
7963                 player->maximum_bitrate[i] = 0;
7964         }
7965
7966         /* free memory related to audio effect */
7967         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7968
7969         if (player->adaptive_info.var_list) {
7970                 g_list_free_full(player->adaptive_info.var_list, g_free);
7971                 player->adaptive_info.var_list = NULL;
7972         }
7973
7974         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7975         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7976         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7977
7978         /* Reset video360 settings to their defaults in case if the pipeline is to be
7979          * re-created.
7980          * */
7981         player->video360_metadata.is_spherical = -1;
7982         player->is_openal_plugin_used = FALSE;
7983
7984         player->is_content_spherical = FALSE;
7985         player->is_video360_enabled = TRUE;
7986         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7987         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7988         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7989         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7990         player->video360_zoom = 1.0f;
7991         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7992         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7993
7994         player->sound.rg_enable = false;
7995
7996         __mmplayer_initialize_video_roi(player);
7997         MMPLAYER_FLEAVE();
7998 }
7999
8000 static void
8001 __mmplayer_release_misc_post(mmplayer_t *player)
8002 {
8003         gchar *original_uri = NULL;
8004         MMPLAYER_FENTER();
8005
8006         /* player->pipeline is already released before. */
8007         MMPLAYER_RETURN_IF_FAIL(player);
8008
8009         player->video_decoded_cb = NULL;
8010         player->video_decoded_cb_user_param = NULL;
8011         player->video_stream_prerolled = false;
8012
8013         player->audio_decoded_cb = NULL;
8014         player->audio_decoded_cb_user_param = NULL;
8015         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
8016
8017         player->audio_stream_changed_cb = NULL;
8018         player->audio_stream_changed_cb_user_param = NULL;
8019
8020         mm_player_set_attribute((MMHandleType)player, NULL,
8021                 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
8022
8023         /* clean found audio decoders */
8024         if (player->audio_decoders) {
8025                 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
8026                 player->audio_decoders = NULL;
8027         }
8028
8029         /* clean the uri list except original uri */
8030         if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
8031                 GList *tmp = NULL;
8032                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
8033                 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
8034                 g_list_free_full(tmp, (GDestroyNotify)g_free);
8035
8036                 if (!original_uri)
8037                         LOGW("failed to get original uri info");
8038
8039                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
8040                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
8041                 MMPLAYER_FREEIF(original_uri);
8042         }
8043
8044         /* clear the audio stream buffer list */
8045         _mmplayer_audio_stream_clear_buffer(player, FALSE);
8046
8047         /* clear the video stream bo list */
8048         __mmplayer_video_stream_destroy_bo_list(player);
8049         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8050
8051         if (player->profile.input_mem.buf) {
8052                 free(player->profile.input_mem.buf);
8053                 player->profile.input_mem.buf = NULL;
8054         }
8055         player->profile.input_mem.len = 0;
8056         player->profile.input_mem.offset = 0;
8057
8058         player->uri_info.uri_idx = 0;
8059         MMPLAYER_FLEAVE();
8060 }
8061
8062 gboolean
8063 __mmplayer_check_subtitle(mmplayer_t *player)
8064 {
8065         MMHandleType attrs = 0;
8066         char *subtitle_uri = NULL;
8067
8068         MMPLAYER_FENTER();
8069
8070         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8071
8072         /* get subtitle attribute */
8073         attrs = MMPLAYER_GET_ATTRS(player);
8074         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
8075
8076         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8077         if (!subtitle_uri || (strlen(subtitle_uri) == 0)) {
8078                 MMPLAYER_FLEAVE();
8079                 return FALSE;
8080         }
8081
8082         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8083
8084         MMPLAYER_FLEAVE();
8085
8086         return TRUE;
8087 }
8088
8089 void
8090 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8091 {
8092         MMPLAYER_RETURN_IF_FAIL(player);
8093
8094         if (player->eos_timer) {
8095                 LOGD("cancel eos timer");
8096                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8097                 player->eos_timer = 0;
8098         }
8099
8100         return;
8101 }
8102
8103 static void
8104 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8105 {
8106         MMPLAYER_FENTER();
8107
8108         MMPLAYER_RETURN_IF_FAIL(player);
8109         MMPLAYER_RETURN_IF_FAIL(sink);
8110
8111         if (first)
8112                 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8113         else
8114                 player->sink_elements = g_list_append(player->sink_elements, sink);
8115
8116         MMPLAYER_FLEAVE();
8117 }
8118
8119 static void
8120 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8121 {
8122         MMPLAYER_FENTER();
8123
8124         MMPLAYER_RETURN_IF_FAIL(player);
8125         MMPLAYER_RETURN_IF_FAIL(sink);
8126
8127         player->sink_elements = g_list_remove(player->sink_elements, sink);
8128
8129         MMPLAYER_FLEAVE();
8130 }
8131
8132 void
8133 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8134         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8135 {
8136         mmplayer_signal_item_t *item = NULL;
8137
8138         MMPLAYER_FENTER();
8139         MMPLAYER_RETURN_IF_FAIL(player);
8140
8141         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8142                 LOGE("invalid signal type [%d]", type);
8143                 return;
8144         }
8145
8146         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8147         if (!item) {
8148                 LOGE("cannot connect signal [%s]", signal);
8149                 return;
8150         }
8151
8152         item->obj = object;
8153         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8154         player->signals[type] = g_list_append(player->signals[type], item);
8155
8156         MMPLAYER_FLEAVE();
8157         return;
8158 }
8159
8160 /* NOTE : be careful with calling this api. please refer to below glib comment
8161  * glib comment : Note that there is a bug in GObject that makes this function much
8162  * less useful than it might seem otherwise. Once gobject is disposed, the callback
8163  * will no longer be called, but, the signal handler is not currently disconnected.
8164  * If the instance is itself being freed at the same time than this doesn't matter,
8165  * since the signal will automatically be removed, but if instance persists,
8166  * then the signal handler will leak. You should not remove the signal yourself
8167  * because in a future versions of GObject, the handler will automatically be
8168  * disconnected.
8169  *
8170  * It's possible to work around this problem in a way that will continue to work
8171  * with future versions of GObject by checking that the signal handler is still
8172  * connected before disconnected it:
8173  *
8174  *  if (g_signal_handler_is_connected(instance, id))
8175  *    g_signal_handler_disconnect(instance, id);
8176  */
8177 static void
8178 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8179 {
8180         GList *sig_list = NULL;
8181         mmplayer_signal_item_t *item = NULL;
8182
8183         MMPLAYER_FENTER();
8184
8185         MMPLAYER_RETURN_IF_FAIL(player);
8186
8187         LOGD("release signals type : %d", type);
8188
8189         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8190                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8191                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8192                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8193                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8194                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8195                 return;
8196         }
8197
8198         sig_list = player->signals[type];
8199
8200         for (; sig_list; sig_list = sig_list->next) {
8201                 item = sig_list->data;
8202
8203                 if (item && item->obj) {
8204                         if (g_signal_handler_is_connected(item->obj, item->sig))
8205                                 g_signal_handler_disconnect(item->obj, item->sig);
8206                 }
8207
8208                 MMPLAYER_FREEIF(item);
8209         }
8210
8211         g_list_free(player->signals[type]);
8212         player->signals[type] = NULL;
8213
8214         MMPLAYER_FLEAVE();
8215
8216         return;
8217 }
8218
8219 int
8220 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8221 {
8222         mmplayer_t *player = 0;
8223         int prev_display_surface_type = 0;
8224
8225         MMPLAYER_FENTER();
8226
8227         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8228
8229         player = MM_PLAYER_CAST(handle);
8230
8231         /* check video sinkbin is created */
8232         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8233                 LOGW("Videosink is already created");
8234                 return MM_ERROR_NONE;
8235         }
8236
8237         LOGD("videosink element is not yet ready");
8238
8239         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8240                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8241                 MMPLAYER_FLEAVE();
8242                 return MM_ERROR_INVALID_ARGUMENT;
8243         }
8244
8245         /* load previous attributes */
8246         if (player->attrs) {
8247                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8248                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8249                 if (prev_display_surface_type == surface_type) {
8250                         LOGD("incoming display surface type is same as previous one, do nothing..");
8251                         MMPLAYER_FLEAVE();
8252                         return MM_ERROR_NONE;
8253                 }
8254         } else {
8255                 LOGE("failed to load attributes");
8256                 MMPLAYER_FLEAVE();
8257                 return MM_ERROR_PLAYER_INTERNAL;
8258         }
8259
8260         /* videobin is not created yet, so we just set attributes related to display surface */
8261         LOGD("store display attribute for given surface type(%d)", surface_type);
8262         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8263                         "display_overlay", wl_surface_id, NULL);
8264
8265         MMPLAYER_FLEAVE();
8266         return MM_ERROR_NONE;
8267 }
8268
8269 /* Note : if silent is true, then subtitle would not be displayed. :*/
8270 int
8271 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8272 {
8273         mmplayer_t *player = (mmplayer_t *)hplayer;
8274
8275         MMPLAYER_FENTER();
8276
8277         /* check player handle */
8278         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8279
8280         player->set_mode.subtitle_off = silent;
8281
8282         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8283
8284         MMPLAYER_FLEAVE();
8285
8286         return MM_ERROR_NONE;
8287 }
8288
8289 int
8290 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8291 {
8292         mmplayer_gst_element_t *mainbin = NULL;
8293         mmplayer_gst_element_t *textbin = NULL;
8294         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8295         GstState current_state = GST_STATE_VOID_PENDING;
8296         GstState element_state = GST_STATE_VOID_PENDING;
8297         GstState element_pending_state = GST_STATE_VOID_PENDING;
8298         gint64 time = 0;
8299         GstEvent *event = NULL;
8300         int result = MM_ERROR_NONE;
8301
8302         GstClock *curr_clock = NULL;
8303         GstClockTime base_time, start_time, curr_time;
8304
8305
8306         MMPLAYER_FENTER();
8307
8308         /* check player handle */
8309         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8310                                                                 player->pipeline &&
8311                                                                 player->pipeline->mainbin &&
8312                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8313
8314         mainbin = player->pipeline->mainbin;
8315         textbin = player->pipeline->textbin;
8316
8317         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8318
8319         // sync clock with current pipeline
8320         curr_clock = gst_element_get_clock(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8321         curr_time = gst_clock_get_time(curr_clock);
8322
8323         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8324         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8325
8326         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8327                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8328
8329         if (current_state > GST_STATE_READY) {
8330                 // sync state with current pipeline
8331                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8332                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8333                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8334
8335                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8336                 if (GST_STATE_CHANGE_FAILURE == ret) {
8337                         LOGE("fail to state change.");
8338                         result = MM_ERROR_PLAYER_INTERNAL;
8339                         if (curr_clock)
8340                                 gst_object_unref(curr_clock);
8341                         goto ERROR;
8342                 }
8343         }
8344         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8345         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8346
8347         if (curr_clock) {
8348                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8349                 gst_object_unref(curr_clock);
8350         }
8351
8352         // seek to current position
8353         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8354                 result = MM_ERROR_PLAYER_INVALID_STATE;
8355                 LOGE("gst_element_query_position failed, invalid state");
8356                 goto ERROR;
8357         }
8358
8359         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8360         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);
8361         if (!event) {
8362                 result = MM_ERROR_PLAYER_INTERNAL;
8363                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8364                 goto ERROR;
8365         }
8366
8367         if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
8368                 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
8369                 if (GST_IS_ELEMENT(text_sink)) {
8370                         if (gst_element_send_event(text_sink, event))
8371                                 LOGD("sending event[%s] to subtitle sink element [%s] success!",
8372                                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(text_sink));
8373                         else
8374                                 LOGE("sending event[%s] to subtitle sink element [%s] failed!",
8375                                                 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(text_sink));
8376                 }
8377         } else {
8378                 _mmplayer_gst_send_event_to_sink(player, event);
8379         }
8380
8381         /* sync state with current pipeline */
8382         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8383         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8384         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8385
8386         return MM_ERROR_NONE;
8387
8388 ERROR:
8389         /* release text pipeline resource */
8390         player->textsink_linked = 0;
8391
8392         /* release signal */
8393         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8394
8395         /* release textbin with it's children */
8396         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8397         MMPLAYER_FREEIF(player->pipeline->textbin);
8398         player->pipeline->textbin = NULL;
8399
8400         /* release subtitle elem */
8401         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8402         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8403
8404         return result;
8405 }
8406
8407 static int
8408 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8409 {
8410         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8411         GstState current_state = GST_STATE_VOID_PENDING;
8412
8413         MMHandleType attrs = 0;
8414         mmplayer_gst_element_t *mainbin = NULL;
8415         mmplayer_gst_element_t *textbin = NULL;
8416
8417         gchar *subtitle_uri = NULL;
8418         int result = MM_ERROR_NONE;
8419         const gchar *charset = NULL;
8420
8421         MMPLAYER_FENTER();
8422
8423         /* check player handle */
8424         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8425                                                                 player->pipeline &&
8426                                                                 player->pipeline->mainbin &&
8427                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8428         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8429
8430         mainbin = player->pipeline->mainbin;
8431         textbin = player->pipeline->textbin;
8432
8433         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8434         if (current_state < GST_STATE_READY) {
8435                 result = MM_ERROR_PLAYER_INVALID_STATE;
8436                 LOGE("Pipeline is not in proper state");
8437                 goto EXIT;
8438         }
8439
8440         attrs = MMPLAYER_GET_ATTRS(player);
8441         if (!attrs) {
8442                 LOGE("cannot get content attribute");
8443                 result = MM_ERROR_PLAYER_INTERNAL;
8444                 goto EXIT;
8445         }
8446
8447         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8448         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8449                 LOGE("subtitle uri is not proper filepath");
8450                 result = MM_ERROR_PLAYER_INVALID_URI;
8451                 goto EXIT;
8452         }
8453
8454         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8455                 LOGE("failed to get storage info of subtitle path");
8456                 result = MM_ERROR_PLAYER_INVALID_URI;
8457                 goto EXIT;
8458         }
8459
8460         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8461         SECURE_LOGD("new subtitle file path is [%s]", filepath);
8462
8463         if (!strcmp(filepath, subtitle_uri)) {
8464                 LOGD("subtitle path is not changed");
8465                 goto EXIT;
8466         } else {
8467                 if (mm_player_set_attribute((MMHandleType)player, NULL,
8468                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8469                         LOGE("failed to set attribute");
8470                         goto EXIT;
8471                 }
8472         }
8473
8474         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8475         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8476         player->subtitle_language_list = NULL;
8477         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8478
8479         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8480         if (ret != GST_STATE_CHANGE_SUCCESS) {
8481                 LOGE("failed to change state of textbin to READY");
8482                 result = MM_ERROR_PLAYER_INTERNAL;
8483                 goto EXIT;
8484         }
8485
8486         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8487         if (ret != GST_STATE_CHANGE_SUCCESS) {
8488                 LOGE("failed to change state of subparse to READY");
8489                 result = MM_ERROR_PLAYER_INTERNAL;
8490                 goto EXIT;
8491         }
8492
8493         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8494         if (ret != GST_STATE_CHANGE_SUCCESS) {
8495                 LOGE("failed to change state of filesrc to READY");
8496                 result = MM_ERROR_PLAYER_INTERNAL;
8497                 goto EXIT;
8498         }
8499
8500         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8501
8502         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8503
8504         charset = _mmplayer_get_charset(filepath);
8505         if (charset) {
8506                 LOGD("detected charset is %s", charset);
8507                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8508         }
8509
8510         result = _mmplayer_sync_subtitle_pipeline(player);
8511
8512 EXIT:
8513         MMPLAYER_FLEAVE();
8514         return result;
8515 }
8516
8517 /* API to switch between external subtitles */
8518 int
8519 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8520 {
8521         int result = MM_ERROR_NONE;
8522         mmplayer_t *player = (mmplayer_t *)hplayer;
8523         char *path = NULL;
8524
8525         MMPLAYER_FENTER();
8526
8527         /* check player handle */
8528         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8529
8530         /* filepath can be null in idle state */
8531         if (filepath) {
8532                 /* check file path */
8533                 if ((path = strstr(filepath, "file://")))
8534                         result = _mmplayer_exist_file_path(path + 7);
8535                 else
8536                         result = _mmplayer_exist_file_path(filepath);
8537
8538                 if (result != MM_ERROR_NONE) {
8539                         LOGE("invalid subtitle path 0x%X", result);
8540                         return result; /* file not found or permission denied */
8541                 }
8542         }
8543
8544         if (!player->pipeline) {
8545                 /* IDLE state */
8546                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8547                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8548                         LOGE("failed to set attribute");
8549                         return MM_ERROR_PLAYER_INTERNAL;
8550                 }
8551         } else {
8552                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8553                 /* check filepath */
8554                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8555
8556                 if (!__mmplayer_check_subtitle(player)) {
8557                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8558                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8559                                 LOGE("failed to set attribute");
8560                                 return MM_ERROR_PLAYER_INTERNAL;
8561                         }
8562
8563                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8564                                 LOGE("fail to create text pipeline");
8565                                 return MM_ERROR_PLAYER_INTERNAL;
8566                         }
8567
8568                         result = _mmplayer_sync_subtitle_pipeline(player);
8569                 } else {
8570                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8571                 }
8572
8573                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8574                 player->is_external_subtitle_added_now = TRUE;
8575
8576                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8577                 if (!player->subtitle_language_list) {
8578                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8579                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8580                                 LOGW("subtitle language list is not updated yet");
8581                 }
8582                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8583         }
8584         player->is_external_subtitle_present = TRUE;
8585
8586         MMPLAYER_FLEAVE();
8587         return result;
8588 }
8589
8590 static int
8591 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8592 {
8593         guint active_idx = 0;
8594         GstStream *stream = NULL;
8595         GList *streams = NULL;
8596         GstCaps *caps = NULL;
8597
8598         MMPLAYER_FENTER();
8599         LOGD("Switching Streams... type: %d, index: %d", type, index);
8600
8601         player->track[type].active_track_index = index;
8602
8603         for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8604                 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8605                 LOGD("track type:%d, total: %d, active: %d", i,
8606                                 player->track[i].total_track_num, player->track[i].active_track_index);
8607                 if (player->track[i].total_track_num > 0 &&
8608                         player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8609                         active_idx = player->track[i].active_track_index;
8610                         stream = g_ptr_array_index(player->track[i].streams, active_idx);
8611                         streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8612                         LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8613
8614                         if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8615                                 caps = gst_stream_get_caps(stream);
8616                                 if (caps) {
8617                                         _mmplayer_set_audio_attrs(player, caps);
8618                                         gst_caps_unref(caps);
8619                                 }
8620                         }
8621                 }
8622         }
8623
8624         if (streams) {
8625                 LOGD("send select stream event");
8626                 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8627                                 gst_event_new_select_streams(streams));
8628                 g_list_free(streams);
8629         }
8630
8631         /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8632         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8633                 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8634
8635                 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8636                         pos_nsec = player->last_position;
8637
8638                 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8639
8640                 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8641                                         player->playback_rate, GST_FORMAT_TIME,
8642                                         (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8643                                         GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8644                         LOGW("failed to seek");
8645                         return MM_ERROR_PLAYER_INTERNAL;
8646                 }
8647         }
8648
8649         MMPLAYER_FLEAVE();
8650         return MM_ERROR_NONE;
8651 }
8652
8653 static int
8654 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8655 {
8656         int result = MM_ERROR_NONE;
8657         gchar *change_pad_name = NULL;
8658         GstPad *sinkpad = NULL;
8659         mmplayer_gst_element_t *mainbin = NULL;
8660         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8661         GstCaps *caps = NULL;
8662         gint total_track_num = 0;
8663
8664         MMPLAYER_FENTER();
8665
8666         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8667                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8668
8669         LOGD("Change Track(%d) to %d", type, index);
8670
8671         mainbin = player->pipeline->mainbin;
8672
8673         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8674                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8675         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8676                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8677         } else {
8678                 /* Changing Video Track is not supported. */
8679                 LOGE("Track Type Error");
8680                 goto EXIT;
8681         }
8682
8683         if (mainbin[elem_idx].gst == NULL) {
8684                 result = MM_ERROR_PLAYER_NO_OP;
8685                 LOGD("Req track doesn't exist");
8686                 goto EXIT;
8687         }
8688
8689         total_track_num = player->track[type].total_track_num;
8690         if (total_track_num <= 0) {
8691                 result = MM_ERROR_PLAYER_NO_OP;
8692                 LOGD("Language list is not available");
8693                 goto EXIT;
8694         }
8695
8696         if ((index < 0) || (index >= total_track_num)) {
8697                 result = MM_ERROR_INVALID_ARGUMENT;
8698                 LOGD("Not a proper index : %d", index);
8699                 goto EXIT;
8700         }
8701
8702         /*To get the new pad from the selector*/
8703         change_pad_name = g_strdup_printf("sink_%u", index);
8704         if (change_pad_name == NULL) {
8705                 result = MM_ERROR_PLAYER_INTERNAL;
8706                 LOGD("Pad does not exists");
8707                 goto EXIT;
8708         }
8709
8710         LOGD("new active pad name: %s", change_pad_name);
8711
8712         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8713         if (sinkpad == NULL) {
8714                 LOGD("sinkpad is NULL");
8715                 result = MM_ERROR_PLAYER_INTERNAL;
8716                 goto EXIT;
8717         }
8718
8719         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8720         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8721
8722         caps = gst_pad_get_current_caps(sinkpad);
8723         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8724
8725         if (sinkpad)
8726                 gst_object_unref(sinkpad);
8727
8728         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8729                 _mmplayer_set_audio_attrs(player, caps);
8730
8731         if (caps)
8732                 gst_caps_unref(caps);
8733
8734 EXIT:
8735         MMPLAYER_FREEIF(change_pad_name);
8736         return result;
8737 }
8738
8739 int
8740 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8741 {
8742         int result = MM_ERROR_NONE;
8743         mmplayer_t *player = NULL;
8744         mmplayer_gst_element_t *mainbin = NULL;
8745
8746         gint current_active_index = 0;
8747
8748         GstState current_state = GST_STATE_VOID_PENDING;
8749         gint64 time = 0;
8750
8751         MMPLAYER_FENTER();
8752
8753         player = (mmplayer_t *)hplayer;
8754         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8755         MMPLAYER_RETURN_VAL_IF_FAIL(type < MM_PLAYER_TRACK_TYPE_MAX, MM_ERROR_PLAYER_NOT_INITIALIZED);
8756
8757         if (!player->pipeline) {
8758                 LOGE("Track %d pre setting -> %d", type, index);
8759
8760                 player->track[type].active_track_index = index;
8761                 goto EXIT;
8762         }
8763
8764         mainbin = player->pipeline->mainbin;
8765
8766         current_active_index = player->track[type].active_track_index;
8767
8768         /*If index is same as running index no need to change the pad*/
8769         if (current_active_index == index)
8770                 goto EXIT;
8771
8772         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8773                 result = MM_ERROR_PLAYER_INVALID_STATE;
8774                 goto EXIT;
8775         }
8776
8777         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8778         if (current_state < GST_STATE_PAUSED) {
8779                 result = MM_ERROR_PLAYER_INVALID_STATE;
8780                 LOGW("Pipeline not in proper state");
8781                 goto EXIT;
8782         }
8783
8784         if (MMPLAYER_USE_DECODEBIN(player))
8785                 result = __mmplayer_change_selector_pad(player, type, index);
8786         else
8787                 result = __mmplayer_switch_stream(player, type, index);
8788
8789         if (result != MM_ERROR_NONE) {
8790                 LOGE("failed to change track");
8791                 goto EXIT;
8792         }
8793
8794         player->track[type].active_track_index = index;
8795
8796         if (MMPLAYER_USE_DECODEBIN(player)) {
8797                 GstEvent *event = NULL;
8798                 if (current_state == GST_STATE_PLAYING) {
8799                         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8800                                 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8801                                 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8802                         if (event) {
8803                                 _mmplayer_gst_send_event_to_sink(player, event);
8804                         } else {
8805                                 result = MM_ERROR_PLAYER_INTERNAL;
8806                                 goto EXIT;
8807                         }
8808                 }
8809         }
8810
8811 EXIT:
8812         return result;
8813 }
8814
8815 int
8816 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8817 {
8818         mmplayer_t *player = (mmplayer_t *)hplayer;
8819
8820         MMPLAYER_FENTER();
8821
8822         /* check player handle */
8823         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8824
8825         *silent = player->set_mode.subtitle_off;
8826
8827         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8828
8829         MMPLAYER_FLEAVE();
8830
8831         return MM_ERROR_NONE;
8832 }
8833
8834 static gboolean
8835 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8836 {
8837         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8838         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8839
8840         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8841         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8842
8843         int idx = 0;
8844
8845         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8846                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8847                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8848                         mmplayer_dump_t *dump_s;
8849                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8850                         if (dump_s == NULL) {
8851                                 LOGE("malloc fail");
8852                                 return FALSE;
8853                         }
8854
8855                         dump_s->dump_element_file = NULL;
8856                         dump_s->dump_pad = NULL;
8857                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8858
8859                         if (dump_s->dump_pad) {
8860                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8861                                 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]);
8862                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8863                                 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);
8864                                 /* add list for removed buffer probe and close FILE */
8865                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8866                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8867                                 return TRUE;
8868                         } else {
8869                                 MMPLAYER_FREEIF(dump_s);
8870                                 LOGE("failed to get %s sink pad added", factory_name);
8871                         }
8872                 }
8873         }
8874         return FALSE;
8875 }
8876
8877 static GstPadProbeReturn
8878 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8879 {
8880         FILE *dump_data = (FILE *)u_data;
8881 //      int written = 0;
8882         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8883         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8884
8885         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8886
8887         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8888 #ifdef __DEBUG__
8889         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8890 #endif
8891         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8892
8893         gst_buffer_unmap(buffer, &probe_info);
8894
8895         return GST_PAD_PROBE_OK;
8896 }
8897
8898 static void
8899 __mmplayer_release_dump_list(GList *dump_list)
8900 {
8901         GList *d_list = dump_list;
8902
8903         if (!d_list)
8904                 return;
8905
8906         for (; d_list; d_list = g_list_next(d_list)) {
8907                 mmplayer_dump_t *dump_s = d_list->data;
8908                 if (dump_s->dump_pad) {
8909                         if (dump_s->probe_handle_id)
8910                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8911                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8912                 }
8913                 if (dump_s->dump_element_file) {
8914                         fclose(dump_s->dump_element_file);
8915                         dump_s->dump_element_file = NULL;
8916                 }
8917                 MMPLAYER_FREEIF(dump_s);
8918         }
8919         g_list_free(dump_list);
8920         dump_list = NULL;
8921 }
8922
8923 int
8924 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8925 {
8926         mmplayer_t *player = (mmplayer_t *)hplayer;
8927
8928         MMPLAYER_FENTER();
8929
8930         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8931         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8932
8933         *exist = (bool)player->has_closed_caption;
8934
8935         MMPLAYER_FLEAVE();
8936
8937         return MM_ERROR_NONE;
8938 }
8939
8940 void
8941 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8942 {
8943         MMPLAYER_FENTER();
8944         if (buffer) {
8945 #ifdef __DEBUG__
8946                 LOGD("unref internal gst buffer %p", buffer);
8947 #endif
8948                 gst_buffer_unref((GstBuffer *)buffer);
8949                 buffer = NULL;
8950         }
8951         MMPLAYER_FLEAVE();
8952 }
8953
8954 int
8955 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8956 {
8957         mmplayer_t *player = (mmplayer_t *)hplayer;
8958
8959         MMPLAYER_FENTER();
8960
8961         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8962         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8963
8964         if (MMPLAYER_IS_STREAMING(player))
8965                 *timeout = (int)player->ini.live_state_change_timeout;
8966         else
8967                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8968
8969         LOGD("timeout = %d", *timeout);
8970
8971         MMPLAYER_FLEAVE();
8972         return MM_ERROR_NONE;
8973 }
8974
8975 static void
8976 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8977 {
8978         int i = 0;
8979         MMPLAYER_FENTER();
8980         MMPLAYER_RETURN_IF_FAIL(player);
8981
8982         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8983
8984                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8985                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8986                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8987                         player->storage_info[i].id = -1;
8988                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8989
8990                         if (path_type != MMPLAYER_PATH_MAX)
8991                                 break;
8992                 }
8993         }
8994
8995         MMPLAYER_FLEAVE();
8996 }
8997
8998 int
8999 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
9000 {
9001         int ret = MM_ERROR_NONE;
9002         mmplayer_t *player = (mmplayer_t *)hplayer;
9003         MMMessageParamType msg_param = {0, };
9004
9005         MMPLAYER_FENTER();
9006         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9007
9008         LOGW("state changed storage %d:%d", id, state);
9009
9010         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
9011                 return MM_ERROR_NONE;
9012
9013         /* FIXME: text path should be handled separately. */
9014         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
9015                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
9016                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
9017                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
9018                 LOGW("external storage is removed");
9019
9020                 if (player->msg_posted == FALSE) {
9021                         memset(&msg_param, 0, sizeof(MMMessageParamType));
9022                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9023                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9024                         player->msg_posted = TRUE;
9025                 }
9026
9027                 /* unrealize the player */
9028                 ret = _mmplayer_unrealize(hplayer);
9029                 if (ret != MM_ERROR_NONE)
9030                         LOGE("failed to unrealize");
9031         }
9032
9033         MMPLAYER_FLEAVE();
9034         return ret;
9035 }
9036
9037 int
9038 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9039 {
9040         int ret = MM_ERROR_NONE;
9041         mmplayer_t *player = (mmplayer_t *)hplayer;
9042         int idx = 0, total = 0;
9043         gchar *result = NULL, *tmp = NULL;
9044
9045         MMPLAYER_FENTER();
9046         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9047         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9048
9049         total = *num = g_list_length(player->adaptive_info.var_list);
9050         if (total <= 0) {
9051                 LOGW("There is no stream variant info.");
9052                 return ret;
9053         }
9054
9055         result = g_strdup("");
9056         for (idx = 0 ; idx < total ; idx++) {
9057                 stream_variant_t *v_data = NULL;
9058                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9059
9060                 if (v_data) {
9061                         gchar data[64] = {0};
9062                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9063
9064                         tmp = g_strconcat(result, data, NULL);
9065                         g_free(result);
9066                         result = tmp;
9067                 } else {
9068                         LOGW("There is no variant data in %d", idx);
9069                         (*num)--;
9070                 }
9071         }
9072
9073         *var_info = (char *)result;
9074
9075         LOGD("variant info %d:%s", *num, *var_info);
9076         MMPLAYER_FLEAVE();
9077         return ret;
9078 }
9079
9080 int
9081 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9082 {
9083         int ret = MM_ERROR_NONE;
9084         mmplayer_t *player = (mmplayer_t *)hplayer;
9085
9086         MMPLAYER_FENTER();
9087         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9088
9089         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9090
9091         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9092         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9093         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9094
9095         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9096                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9097                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9098                                                 "max-bitrate", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9099
9100                 /* FIXME: seek to current position for applying new variant limitation */
9101         }
9102
9103         MMPLAYER_FLEAVE();
9104         return ret;
9105
9106 }
9107
9108 int
9109 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9110 {
9111         int ret = MM_ERROR_NONE;
9112         mmplayer_t *player = (mmplayer_t *)hplayer;
9113
9114         MMPLAYER_FENTER();
9115         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9116         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9117
9118         *bandwidth = player->adaptive_info.limit.bandwidth;
9119         *width = player->adaptive_info.limit.width;
9120         *height = player->adaptive_info.limit.height;
9121
9122         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9123
9124         MMPLAYER_FLEAVE();
9125         return ret;
9126 }
9127
9128 int
9129 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9130 {
9131         int ret = MM_ERROR_NONE;
9132         mmplayer_t *player = (mmplayer_t *)hplayer;
9133
9134         MMPLAYER_FENTER();
9135         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9136         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9137         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9138
9139         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9140
9141         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9142                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9143         else /* live case */
9144                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9145
9146         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9147
9148         MMPLAYER_FLEAVE();
9149         return ret;
9150 }
9151
9152 int
9153 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9154 {
9155 #define IDX_FIRST_SW_CODEC 0
9156         mmplayer_t *player = (mmplayer_t *)hplayer;
9157         int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9158         const char *attr_name = NULL;
9159         const char *default_type = NULL;
9160         const char *element_hw = NULL;
9161         const char *element_sw = NULL;
9162
9163         MMPLAYER_FENTER();
9164         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9165
9166         LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9167
9168         /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9169         switch (stream_type) {
9170         case MM_PLAYER_STREAM_TYPE_AUDIO:
9171                 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9172                 default_type = player->ini.audiocodec_default_type;
9173                 element_hw = player->ini.audiocodec_element_hw;
9174                 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9175                 break;
9176         case MM_PLAYER_STREAM_TYPE_VIDEO:
9177                 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9178                 default_type = player->ini.videocodec_default_type;
9179                 element_hw = player->ini.videocodec_element_hw;
9180                 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9181                 break;
9182         default:
9183                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9184                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9185                 break;
9186         }
9187
9188         LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9189
9190         if (!strcmp(default_type, "sw"))
9191                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9192         else
9193                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9194
9195         if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9196                 codec_type = default_codec_type;
9197
9198         /* to support codec selection, codec info have to be added in ini file.
9199            in case of hw codec is selected, filter elements should be applied
9200            depending on the hw capabilities. */
9201         if (codec_type != default_codec_type) {
9202                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9203                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9204                         LOGE("There is no codec for type %d", codec_type);
9205                         return MM_ERROR_PLAYER_NO_OP;
9206                 }
9207
9208                 LOGD("sorting is required");
9209                 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9210                         player->need_audio_dec_sorting = TRUE;
9211                 else
9212                         player->need_video_dec_sorting = TRUE;
9213         }
9214
9215         LOGD("update %s codec_type to %d", attr_name, codec_type);
9216         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9217
9218         MMPLAYER_FLEAVE();
9219         return MM_ERROR_NONE;
9220 }
9221
9222 int
9223 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9224 {
9225         mmplayer_t *player = (mmplayer_t *)hplayer;
9226         GstElement *rg_vol_element = NULL;
9227
9228         MMPLAYER_FENTER();
9229
9230         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9231
9232         player->sound.rg_enable = enabled;
9233
9234         /* just hold rgvolume enable value if pipeline is not ready */
9235         if (!player->pipeline || !player->pipeline->audiobin) {
9236                 LOGD("pipeline is not ready. holding rgvolume enable value");
9237                 return MM_ERROR_NONE;
9238         }
9239
9240         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9241
9242         if (!rg_vol_element) {
9243                 LOGD("rgvolume element is not created");
9244                 return MM_ERROR_PLAYER_INTERNAL;
9245         }
9246
9247         if (enabled)
9248                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9249         else
9250                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9251
9252         MMPLAYER_FLEAVE();
9253
9254         return MM_ERROR_NONE;
9255 }
9256
9257 int
9258 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9259 {
9260         mmplayer_t *player = (mmplayer_t *)hplayer;
9261         GstElement *rg_vol_element = NULL;
9262         gboolean enable = FALSE;
9263
9264         MMPLAYER_FENTER();
9265
9266         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9267         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9268
9269         /* just hold enable_rg value if pipeline is not ready */
9270         if (!player->pipeline || !player->pipeline->audiobin) {
9271                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9272                 *enabled = player->sound.rg_enable;
9273                 return MM_ERROR_NONE;
9274         }
9275
9276         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9277
9278         if (!rg_vol_element) {
9279                 LOGD("rgvolume element is not created");
9280                 return MM_ERROR_PLAYER_INTERNAL;
9281         }
9282
9283         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9284         *enabled = (bool)enable;
9285
9286         MMPLAYER_FLEAVE();
9287
9288         return MM_ERROR_NONE;
9289 }
9290
9291 int
9292 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9293 {
9294         mmplayer_t *player = (mmplayer_t *)hplayer;
9295         MMHandleType attrs = 0;
9296         int handle = 0;
9297         int ret = MM_ERROR_NONE;
9298
9299         MMPLAYER_FENTER();
9300
9301         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9302
9303         attrs = MMPLAYER_GET_ATTRS(player);
9304         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9305
9306         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9307         if (!handle) {
9308                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9309                 return MM_ERROR_PLAYER_INTERNAL;
9310         }
9311
9312         player->video_roi.scale_x = scale_x;
9313         player->video_roi.scale_y = scale_y;
9314         player->video_roi.scale_width = scale_width;
9315         player->video_roi.scale_height = scale_height;
9316
9317         /* check video sinkbin is created */
9318         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9319                 return MM_ERROR_NONE;
9320
9321         if (!gst_video_overlay_set_video_roi_area(
9322                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9323                 scale_x, scale_y, scale_width, scale_height))
9324                 ret = MM_ERROR_PLAYER_INTERNAL;
9325         else
9326                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9327                         scale_x, scale_y, scale_width, scale_height);
9328
9329         MMPLAYER_FLEAVE();
9330
9331         return ret;
9332 }
9333
9334 int
9335 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9336 {
9337         mmplayer_t *player = (mmplayer_t *)hplayer;
9338         int ret = MM_ERROR_NONE;
9339
9340         MMPLAYER_FENTER();
9341
9342         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9343         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9344
9345         *scale_x = player->video_roi.scale_x;
9346         *scale_y = player->video_roi.scale_y;
9347         *scale_width = player->video_roi.scale_width;
9348         *scale_height = player->video_roi.scale_height;
9349
9350         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9351                 *scale_x, *scale_y, *scale_width, *scale_height);
9352
9353         return ret;
9354 }
9355
9356 int
9357 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9358 {
9359         mmplayer_t *player = (mmplayer_t *)hplayer;
9360
9361         MMPLAYER_FENTER();
9362
9363         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9364
9365         player->client_pid = pid;
9366
9367         LOGD("client pid[%d] %p", pid, player);
9368
9369         MMPLAYER_FLEAVE();
9370
9371         return MM_ERROR_NONE;
9372 }
9373
9374 int
9375 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9376 {
9377         mmplayer_t *player = (mmplayer_t *)hplayer;
9378         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9379         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9380
9381         MMPLAYER_FENTER();
9382
9383         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9384         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9385
9386         *available = true;
9387         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9388
9389         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9390
9391         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9392                 return MM_ERROR_NONE;
9393
9394         /* in case of audio codec default type is HW */
9395         switch(opt) {
9396                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9397                         if (player->ini.support_audio_effect)
9398                                 return MM_ERROR_NONE;
9399                         elem_id = MMPLAYER_A_FILTER;
9400                 break;
9401                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9402                         if (player->ini.support_replaygain_control)
9403                                 return MM_ERROR_NONE;
9404                         elem_id = MMPLAYER_A_RGVOL;
9405                 break;
9406                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9407                         if (player->ini.support_pitch_control)
9408                                 return MM_ERROR_NONE;
9409                         elem_id = MMPLAYER_A_PITCH;
9410                 break;
9411                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9412                         if (player->ini.support_audio_effect)
9413                                 return MM_ERROR_NONE;
9414                 break;
9415                 /* default case handling is not required */
9416         }
9417
9418         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9419                 LOGW("audio control option [%d] is not available", opt);
9420                 *available = false;
9421         } else {
9422                 /* setting pcm exporting option is allowed before READY state */
9423                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9424                         return MM_ERROR_PLAYER_INVALID_STATE;
9425
9426                 /* check whether the audio filter exist or not after READY state,
9427                    because the sw codec could be added during auto-plugging in some cases */
9428                 if (!player->pipeline ||
9429                         !player->pipeline->audiobin ||
9430                         !player->pipeline->audiobin[elem_id].gst) {
9431                         LOGW("there is no audio elem [%d]", elem_id);
9432                         *available = false;
9433                 }
9434         }
9435
9436         LOGD("audio control opt %d, available %d", opt, *available);
9437
9438         MMPLAYER_FLEAVE();
9439
9440         return MM_ERROR_NONE;
9441 }
9442
9443 static gboolean
9444 __mmplayer_update_duration_value(mmplayer_t *player)
9445 {
9446         gboolean ret = FALSE;
9447         gint64 dur_nsec = 0;
9448         LOGD("try to update duration");
9449
9450         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9451                 player->duration = dur_nsec;
9452                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9453                 ret = TRUE;
9454         }
9455
9456         if (player->duration < 0) {
9457                 LOGW("duration is Non-Initialized !!!");
9458                 player->duration = 0;
9459         }
9460
9461         /* update streaming service type */
9462         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9463
9464         /* check duration is OK */
9465         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9466                 /* FIXIT : find another way to get duration here. */
9467                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9468
9469         return ret;
9470 }
9471
9472 static gboolean
9473 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9474 {
9475         /* update audio params
9476         NOTE : We need original audio params and it can be only obtained from src pad of audio
9477         decoder. Below code only valid when we are not using 'resampler' just before
9478         'audioconverter'. */
9479         GstCaps *caps_a = NULL;
9480         GstPad *pad = NULL;
9481         gint samplerate = 0, channels = 0;
9482         GstStructure *p = NULL;
9483         GstElement *aconv = NULL;
9484
9485         LOGD("try to update audio attrs");
9486
9487         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9488
9489         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9490                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9491         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9492                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9493         } else {
9494                 LOGE("there is no audio converter");
9495                 return FALSE;
9496         }
9497
9498         pad = gst_element_get_static_pad(aconv, "sink");
9499
9500         if (!pad) {
9501                 LOGW("failed to get pad from audio converter");
9502                 return FALSE;
9503         }
9504
9505         caps_a = gst_pad_get_current_caps(pad);
9506         if (!caps_a) {
9507                 LOGW("not ready to get audio caps");
9508                 gst_object_unref(pad);
9509                 return FALSE;
9510         }
9511
9512         p = gst_caps_get_structure(caps_a, 0);
9513         gst_structure_get_int(p, "rate", &samplerate);
9514         gst_structure_get_int(p, "channels", &channels);
9515
9516         mm_player_set_attribute((MMHandleType)player, NULL,
9517                         "content_audio_samplerate", samplerate,
9518                         "content_audio_channels", channels, NULL);
9519
9520         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9521
9522         gst_caps_unref(caps_a);
9523         gst_object_unref(pad);
9524
9525         return TRUE;
9526 }
9527
9528 static gboolean
9529 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9530 {
9531         LOGD("try to update video attrs");
9532
9533         GstCaps *caps_v = NULL;
9534         GstPad *pad = NULL;
9535         gint tmpNu, tmpDe;
9536         gint width, height;
9537         GstStructure *p = NULL;
9538
9539         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9540         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9541
9542         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9543         if (!pad) {
9544                 LOGD("no videosink sink pad");
9545                 return FALSE;
9546         }
9547
9548         caps_v = gst_pad_get_current_caps(pad);
9549         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9550         if (!caps_v && player->v_stream_caps) {
9551                 caps_v = player->v_stream_caps;
9552                 gst_caps_ref(caps_v);
9553         }
9554
9555         if (!caps_v) {
9556                 LOGD("no negotiated caps from videosink");
9557                 gst_object_unref(pad);
9558                 return FALSE;
9559         }
9560
9561         p = gst_caps_get_structure(caps_v, 0);
9562         gst_structure_get_int(p, "width", &width);
9563         gst_structure_get_int(p, "height", &height);
9564
9565         mm_player_set_attribute((MMHandleType)player, NULL,
9566                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9567
9568         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9569
9570         SECURE_LOGD("width : %d     height : %d", width, height);
9571
9572         gst_caps_unref(caps_v);
9573         gst_object_unref(pad);
9574
9575         if (tmpDe > 0) {
9576                 mm_player_set_attribute((MMHandleType)player, NULL,
9577                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9578                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9579         }
9580
9581         return TRUE;
9582 }
9583
9584 static gboolean
9585 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9586 {
9587         gboolean ret = FALSE;
9588         guint64 data_size = 0;
9589         gchar *path = NULL;
9590         struct stat sb;
9591
9592         /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9593         if (!player->duration)
9594                 return FALSE;
9595
9596         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9597                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9598                 if (stat(path, &sb) == 0)
9599                         data_size = (guint64)sb.st_size;
9600
9601         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9602                 data_size = player->http_content_size;
9603         }
9604
9605         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9606
9607         if (data_size) {
9608                 guint64 bitrate = 0;
9609                 guint64 msec_dur = 0;
9610
9611                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9612                 if (msec_dur > 0) {
9613                         bitrate = data_size * 8 * 1000 / msec_dur;
9614                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9615                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9616                         mm_player_set_attribute((MMHandleType)player, NULL,
9617                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9618                         ret = TRUE;
9619                 } else {
9620                         LOGD("player duration is less than 0");
9621                 }
9622         }
9623
9624         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9625                 if (player->total_bitrate) {
9626                         mm_player_set_attribute((MMHandleType)player, NULL,
9627                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9628                         ret = TRUE;
9629                 }
9630         }
9631
9632         return ret;
9633 }
9634
9635 static void
9636 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9637 {
9638         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9639         data->uri_type = uri_type;
9640 }
9641
9642 static int
9643 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9644 {
9645         int ret = MM_ERROR_PLAYER_INVALID_URI;
9646         int mem_size = 0;
9647         char *buffer = NULL;
9648         char *seperator = strchr(path, ',');
9649         char ext[100] = {0,}, size[100] = {0,};
9650
9651         if (seperator) {
9652                 if ((buffer = strstr(path, "ext="))) {
9653                         buffer += strlen("ext=");
9654
9655                         if (strlen(buffer)) {
9656                                 strncpy(ext, buffer, 99);
9657
9658                                 if ((seperator = strchr(ext, ','))
9659                                         || (seperator = strchr(ext, ' '))
9660                                         || (seperator = strchr(ext, '\0'))) {
9661                                         seperator[0] = '\0';
9662                                 }
9663                         }
9664                 }
9665
9666                 if ((buffer = strstr(path, "size="))) {
9667                         buffer += strlen("size=");
9668
9669                         if (strlen(buffer) > 0) {
9670                                 strncpy(size, buffer, 99);
9671
9672                                 if ((seperator = strchr(size, ','))
9673                                         || (seperator = strchr(size, ' '))
9674                                         || (seperator = strchr(size, '\0'))) {
9675                                         seperator[0] = '\0';
9676                                 }
9677
9678                                 mem_size = atoi(size);
9679                         }
9680                 }
9681         }
9682
9683         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9684
9685         if (mem_size && param) {
9686                 if (data->input_mem.buf)
9687                         free(data->input_mem.buf);
9688                 data->input_mem.buf = malloc(mem_size);
9689
9690                 if (data->input_mem.buf) {
9691                         memcpy(data->input_mem.buf, param, mem_size);
9692                         data->input_mem.len = mem_size;
9693                         ret = MM_ERROR_NONE;
9694                 } else {
9695                         LOGE("failed to alloc mem %d", mem_size);
9696                         ret = MM_ERROR_PLAYER_INTERNAL;
9697                 }
9698
9699                 data->input_mem.offset = 0;
9700                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9701         }
9702
9703         return ret;
9704 }
9705
9706 static int
9707 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9708 {
9709         gchar *location = NULL;
9710         GError *err = NULL;
9711         char *path = NULL;
9712         int ret = MM_ERROR_NONE;
9713
9714         if ((path = strstr(uri, "file://"))) {
9715                 location = g_filename_from_uri(uri, NULL, &err);
9716                 if (!location || (err != NULL)) {
9717                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9718                                 (err != NULL) ? err->message : "unknown error");
9719                         if (err)
9720                                 g_error_free(err);
9721
9722                         MMPLAYER_FREEIF(location);
9723
9724                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9725                         return MM_ERROR_PLAYER_INVALID_URI;
9726                 }
9727                 LOGD("path from uri: %s", location);
9728         }
9729
9730         path = (location != NULL) ? (location) : ((char *)uri);
9731
9732
9733         ret = _mmplayer_exist_file_path(path);
9734
9735         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9736         if (ret == MM_ERROR_NONE) {
9737                 if (_mmplayer_is_sdp_file(path)) {
9738                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9739                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9740                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9741                 } else {
9742                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9743                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9744                 }
9745         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9746                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9747         } else {
9748                 LOGE("invalid uri, could not play..");
9749                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9750         }
9751
9752         MMPLAYER_FREEIF(location);
9753
9754         return ret;
9755 }
9756
9757 static mmplayer_video_decoded_data_info_t *
9758 __mmplayer_create_stream_from_pad(GstPad *pad)
9759 {
9760         GstCaps *caps = NULL;
9761         GstStructure *structure = NULL;
9762         unsigned int fourcc = 0;
9763         const gchar *string_format = NULL;
9764         mmplayer_video_decoded_data_info_t *stream = NULL;
9765         gint width, height;
9766         MMPixelFormatType format;
9767         GstVideoInfo info;
9768
9769         caps = gst_pad_get_current_caps(pad);
9770         if (!caps) {
9771                 LOGE("Caps is NULL.");
9772                 return NULL;
9773         }
9774
9775 #ifdef __DEBUG__
9776         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9777 #endif
9778         structure = gst_caps_get_structure(caps, 0);
9779         gst_structure_get_int(structure, "width", &width);
9780         gst_structure_get_int(structure, "height", &height);
9781         string_format = gst_structure_get_string(structure, "format");
9782
9783         if (string_format)
9784                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9785         format = _mmplayer_get_pixtype(fourcc);
9786         gst_video_info_from_caps(&info, caps);
9787         gst_caps_unref(caps);
9788
9789         /* moved here */
9790         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9791                 LOGE("Wrong condition!!");
9792                 return NULL;
9793         }
9794
9795         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9796         if (!stream) {
9797                 LOGE("failed to alloc mem for video data");
9798                 return NULL;
9799         }
9800
9801         stream->width = width;
9802         stream->height = height;
9803         stream->format = format;
9804         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9805
9806         return stream;
9807 }
9808
9809 static void
9810 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9811 {
9812         unsigned int pitch = 0;
9813         unsigned int size = 0;
9814         int index = 0;
9815         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9816         tbm_bo bo = NULL;
9817
9818         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9819                 bo = gst_tizen_memory_get_bos(mem, index);
9820                 if (bo)
9821                         stream->bo[index] = tbm_bo_ref(bo);
9822                 else
9823                         LOGE("failed to get bo for index %d", index);
9824         }
9825
9826         for (index = 0; index < stream->plane_num; index++) {
9827                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9828                 stream->stride[index] = pitch;
9829                 if (pitch)
9830                         stream->elevation[index] = size / pitch;
9831                 else
9832                         stream->elevation[index] = stream->height;
9833         }
9834 }
9835
9836 static gboolean
9837 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9838 {
9839         if (stream->format == MM_PIXEL_FORMAT_I420) {
9840                 int ret = TBM_SURFACE_ERROR_NONE;
9841                 tbm_surface_h surface;
9842                 tbm_surface_info_s info;
9843
9844                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9845
9846                 ret = tbm_surface_get_info(surface, &info);
9847                 if (ret != TBM_SURFACE_ERROR_NONE) {
9848                         tbm_surface_destroy(surface);
9849                         return FALSE;
9850                 }
9851
9852                 tbm_surface_destroy(surface);
9853                 stream->stride[0] = info.planes[0].stride;
9854                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9855                 stream->stride[1] = info.planes[1].stride;
9856                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9857                 stream->stride[2] = info.planes[2].stride;
9858                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9859                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9860         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9861                 stream->stride[0] = stream->width * 4;
9862                 stream->elevation[0] = stream->height;
9863                 stream->bo_size = stream->stride[0] * stream->height;
9864         } else {
9865                 LOGE("Not support format %d", stream->format);
9866                 return FALSE;
9867         }
9868
9869         return TRUE;
9870 }
9871
9872 static gboolean
9873 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9874 {
9875         tbm_bo_handle thandle;
9876         gboolean is_mapped;
9877         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9878         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9879         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9880         int i = 0;
9881         int j = 0;
9882         int k = 0;
9883         unsigned char *src = NULL;
9884         unsigned char *dest = NULL;
9885         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9886
9887         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9888         if (!is_mapped) {
9889                 LOGE("fail to gst_memory_map");
9890                 return FALSE;
9891         }
9892
9893         if (!mapinfo.data) {
9894                 LOGE("data pointer is wrong");
9895                 goto ERROR;
9896         }
9897
9898         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9899         if (!stream->bo[0]) {
9900                 LOGE("Fail to tbm_bo_alloc!!");
9901                 goto ERROR;
9902         }
9903
9904         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9905         if (!thandle.ptr) {
9906                 LOGE("thandle pointer is wrong");
9907                 goto ERROR;
9908         }
9909
9910         if (stream->format == MM_PIXEL_FORMAT_I420) {
9911                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9912                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9913                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9914                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9915
9916                 dest_offset[0] = 0;
9917                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9918                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9919
9920                 for (i = 0; i < 3; i++) {
9921                         src = mapinfo.data + src_offset[i];
9922                         dest = thandle.ptr + dest_offset[i];
9923
9924                         if (i > 0)
9925                                 k = 1;
9926
9927                         for (j = 0; j < stream->height >> k; j++) {
9928                                 memcpy(dest, src, stream->width>>k);
9929                                 src += src_stride[i];
9930                                 dest += stream->stride[i];
9931                         }
9932                 }
9933         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9934                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9935         } else {
9936                 LOGE("Not support format %d", stream->format);
9937                 goto ERROR;
9938         }
9939
9940         tbm_bo_unmap(stream->bo[0]);
9941         gst_memory_unmap(mem, &mapinfo);
9942
9943         return TRUE;
9944
9945 ERROR:
9946         if (stream->bo[0])
9947                 tbm_bo_unmap(stream->bo[0]);
9948
9949         if (is_mapped)
9950                 gst_memory_unmap(mem, &mapinfo);
9951
9952         return FALSE;
9953 }
9954
9955 static void
9956 __mmplayer_set_pause_state(mmplayer_t *player)
9957 {
9958         if (player->sent_bos)
9959                 return;
9960
9961         /* rtsp case, get content attrs by GstMessage */
9962         if (MMPLAYER_IS_RTSP_STREAMING(player))
9963                 return;
9964
9965         /* it's first time to update all content attrs. */
9966         _mmplayer_update_content_attrs(player, ATTR_ALL);
9967 }
9968
9969 static void
9970 __mmplayer_set_playing_state(mmplayer_t *player)
9971 {
9972         gchar *audio_codec = NULL;
9973
9974         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9975                 /* initialize because auto resume is done well. */
9976                 player->resumed_by_rewind = FALSE;
9977                 player->playback_rate = 1.0;
9978         }
9979
9980         if (player->sent_bos)
9981                 return;
9982
9983         /* try to get content metadata */
9984
9985         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9986          * c-api since c-api doesn't use _start() anymore. It may not work properly with
9987          * legacy mmfw-player api
9988          */
9989         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9990
9991         if ((player->cmd == MMPLAYER_COMMAND_START)
9992                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9993                 __mmplayer_handle_missed_plugin(player);
9994         }
9995
9996         /* check audio codec field is set or not
9997          * we can get it from typefinder or codec's caps.
9998          */
9999         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
10000
10001         /* The codec format can't be sent for audio only case like amr, mid etc.
10002          * Because, parser don't make related TAG.
10003          * So, if it's not set yet, fill it with found data.
10004          */
10005         if (!audio_codec) {
10006                 if (g_strrstr(player->type_caps_str, "audio/midi"))
10007                         audio_codec = "MIDI";
10008                 else if (g_strrstr(player->type_caps_str, "audio/x-amr"))
10009                         audio_codec = "AMR";
10010                 else if (g_strrstr(player->type_caps_str, "audio/mpeg")
10011                                 && !g_strrstr(player->type_caps_str, "mpegversion=(int)1"))
10012                         audio_codec = "AAC";
10013                 else
10014                         audio_codec = "unknown";
10015
10016                 if (mm_player_set_attribute((MMHandleType)player, NULL,
10017                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
10018                         LOGE("failed to set attribute");
10019
10020                 LOGD("set audio codec type with caps");
10021         }
10022
10023         return;
10024 }