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