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