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