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