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