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