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