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