[0.6.183] Fix bug that calculates the stream elevation value
[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 (player->audio_device_cb_id > 0 &&
7519                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7520                 LOGW("failed to remove audio device_connected_callback");
7521         player->audio_device_cb_id = 0;
7522
7523         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7524                 player->bitrate[i] = 0;
7525                 player->maximum_bitrate[i] = 0;
7526         }
7527
7528         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7529
7530         /* remove media stream cb(appsrc cb) */
7531         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7532                 player->media_stream_buffer_status_cb[i] = NULL;
7533                 player->media_stream_seek_data_cb[i] = NULL;
7534                 player->buffer_cb_user_param[i] = NULL;
7535                 player->seek_cb_user_param[i] = NULL;
7536         }
7537         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7538
7539         /* free memory related to audio effect */
7540         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7541
7542         if (player->adaptive_info.var_list) {
7543                 g_list_free_full(player->adaptive_info.var_list, g_free);
7544                 player->adaptive_info.var_list = NULL;
7545         }
7546
7547         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7548         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7549         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7550
7551         /* Reset video360 settings to their defaults in case if the pipeline is to be
7552          * re-created.
7553          * */
7554         player->video360_metadata.is_spherical = -1;
7555         player->is_openal_plugin_used = FALSE;
7556
7557         player->is_content_spherical = FALSE;
7558         player->is_video360_enabled = TRUE;
7559         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7560         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7561         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7562         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7563         player->video360_zoom = 1.0f;
7564         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7565         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7566
7567         player->sound.rg_enable = false;
7568
7569         __mmplayer_initialize_video_roi(player);
7570         MMPLAYER_FLEAVE();
7571 }
7572
7573 static void
7574 __mmplayer_release_misc_post(mmplayer_t *player)
7575 {
7576         char *original_uri = NULL;
7577         MMPLAYER_FENTER();
7578
7579         /* player->pipeline is already released before. */
7580
7581         MMPLAYER_RETURN_IF_FAIL(player);
7582
7583         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7584
7585         /* clean found audio decoders */
7586         if (player->audio_decoders) {
7587                 GList *a_dec = player->audio_decoders;
7588                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7589                         gchar *name = a_dec->data;
7590                         MMPLAYER_FREEIF(name);
7591                 }
7592                 g_list_free(player->audio_decoders);
7593                 player->audio_decoders = NULL;
7594         }
7595
7596         /* clean the uri list except original uri */
7597         if (player->uri_info.uri_list) {
7598                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7599
7600                 if (player->attrs) {
7601                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7602                         LOGD("restore original uri = %s", original_uri);
7603
7604                         if (mm_attrs_commit_all(player->attrs))
7605                                 LOGE("failed to commit the original uri.");
7606                 }
7607
7608                 GList *uri_list = player->uri_info.uri_list;
7609                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7610                         gchar *uri = uri_list->data;
7611                         MMPLAYER_FREEIF(uri);
7612                 }
7613                 g_list_free(player->uri_info.uri_list);
7614                 player->uri_info.uri_list = NULL;
7615         }
7616
7617         /* clear the audio stream buffer list */
7618         __mmplayer_audio_stream_clear_buffer(player, FALSE);
7619
7620         /* clear the video stream bo list */
7621         __mmplayer_video_stream_destroy_bo_list(player);
7622         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7623
7624         if (player->profile.input_mem.buf) {
7625                 free(player->profile.input_mem.buf);
7626                 player->profile.input_mem.buf = NULL;
7627         }
7628         player->profile.input_mem.len = 0;
7629         player->profile.input_mem.offset = 0;
7630
7631         player->uri_info.uri_idx = 0;
7632         MMPLAYER_FLEAVE();
7633 }
7634
7635 gboolean
7636 __mmplayer_check_subtitle(mmplayer_t *player)
7637 {
7638         MMHandleType attrs = 0;
7639         char *subtitle_uri = NULL;
7640
7641         MMPLAYER_FENTER();
7642
7643         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7644
7645         /* get subtitle attribute */
7646         attrs = MMPLAYER_GET_ATTRS(player);
7647         if (!attrs)
7648                 return FALSE;
7649
7650         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7651         if (!subtitle_uri || !strlen(subtitle_uri))
7652                 return FALSE;
7653
7654         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7655         player->is_external_subtitle_present = TRUE;
7656
7657         MMPLAYER_FLEAVE();
7658
7659         return TRUE;
7660 }
7661
7662 void
7663 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7664 {
7665         MMPLAYER_RETURN_IF_FAIL(player);
7666
7667         if (player->eos_timer) {
7668                 LOGD("cancel eos timer");
7669                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7670                 player->eos_timer = 0;
7671         }
7672
7673         return;
7674 }
7675
7676 static void
7677 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7678 {
7679         MMPLAYER_FENTER();
7680
7681         MMPLAYER_RETURN_IF_FAIL(player);
7682         MMPLAYER_RETURN_IF_FAIL(sink);
7683
7684         player->sink_elements = g_list_append(player->sink_elements, sink);
7685
7686         MMPLAYER_FLEAVE();
7687 }
7688
7689 static void
7690 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7691 {
7692         MMPLAYER_FENTER();
7693
7694         MMPLAYER_RETURN_IF_FAIL(player);
7695         MMPLAYER_RETURN_IF_FAIL(sink);
7696
7697         player->sink_elements = g_list_remove(player->sink_elements, sink);
7698
7699         MMPLAYER_FLEAVE();
7700 }
7701
7702 void
7703 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7704         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7705 {
7706         mmplayer_signal_item_t *item = NULL;
7707
7708         MMPLAYER_FENTER();
7709         MMPLAYER_RETURN_IF_FAIL(player);
7710
7711         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7712                 LOGE("invalid signal type [%d]", type);
7713                 return;
7714         }
7715
7716         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7717         if (!item) {
7718                 LOGE("cannot connect signal [%s]", signal);
7719                 return;
7720         }
7721
7722         item->obj = object;
7723         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7724         player->signals[type] = g_list_append(player->signals[type], item);
7725
7726         MMPLAYER_FLEAVE();
7727         return;
7728 }
7729
7730 /* NOTE : be careful with calling this api. please refer to below glib comment
7731  * glib comment : Note that there is a bug in GObject that makes this function much
7732  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7733  * will no longer be called, but, the signal handler is not currently disconnected.
7734  * If the instance is itself being freed at the same time than this doesn't matter,
7735  * since the signal will automatically be removed, but if instance persists,
7736  * then the signal handler will leak. You should not remove the signal yourself
7737  * because in a future versions of GObject, the handler will automatically be
7738  * disconnected.
7739  *
7740  * It's possible to work around this problem in a way that will continue to work
7741  * with future versions of GObject by checking that the signal handler is still
7742  * connected before disconnected it:
7743  *
7744  *  if (g_signal_handler_is_connected(instance, id))
7745  *    g_signal_handler_disconnect(instance, id);
7746  */
7747 static void
7748 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7749 {
7750         GList *sig_list = NULL;
7751         mmplayer_signal_item_t *item = NULL;
7752
7753         MMPLAYER_FENTER();
7754
7755         MMPLAYER_RETURN_IF_FAIL(player);
7756
7757         LOGD("release signals type : %d", type);
7758
7759         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7760                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7761                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7762                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7763                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7764                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7765                 return;
7766         }
7767
7768         sig_list = player->signals[type];
7769
7770         for (; sig_list; sig_list = sig_list->next) {
7771                 item = sig_list->data;
7772
7773                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7774                         if (g_signal_handler_is_connected(item->obj, item->sig))
7775                                 g_signal_handler_disconnect(item->obj, item->sig);
7776                 }
7777
7778                 MMPLAYER_FREEIF(item);
7779         }
7780
7781         g_list_free(player->signals[type]);
7782         player->signals[type] = NULL;
7783
7784         MMPLAYER_FLEAVE();
7785
7786         return;
7787 }
7788
7789 int
7790 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7791 {
7792         mmplayer_t *player = 0;
7793         int prev_display_surface_type = 0;
7794         void *prev_display_overlay = NULL;
7795
7796         MMPLAYER_FENTER();
7797
7798         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7799         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7800
7801         player = MM_PLAYER_CAST(handle);
7802
7803         /* check video sinkbin is created */
7804         if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7805                 LOGE("Videosink is already created");
7806                 return MM_ERROR_NONE;
7807         }
7808
7809         LOGD("videosink element is not yet ready");
7810
7811         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7812                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7813                 MMPLAYER_FLEAVE();
7814                 return MM_ERROR_INVALID_ARGUMENT;
7815         }
7816
7817         /* load previous attributes */
7818         if (player->attrs) {
7819                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7820                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7821                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7822                 if (prev_display_surface_type == surface_type) {
7823                         LOGD("incoming display surface type is same as previous one, do nothing..");
7824                         MMPLAYER_FLEAVE();
7825                         return MM_ERROR_NONE;
7826                 }
7827         } else {
7828                 LOGE("failed to load attributes");
7829                 MMPLAYER_FLEAVE();
7830                 return MM_ERROR_PLAYER_INTERNAL;
7831         }
7832
7833         /* videobin is not created yet, so we just set attributes related to display surface */
7834         LOGD("store display attribute for given surface type(%d)", surface_type);
7835         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7836         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7837         if (mm_attrs_commit_all(player->attrs)) {
7838                 LOGE("failed to commit attribute");
7839                 MMPLAYER_FLEAVE();
7840                 return MM_ERROR_PLAYER_INTERNAL;
7841         }
7842
7843         MMPLAYER_FLEAVE();
7844         return MM_ERROR_NONE;
7845 }
7846
7847 /* Note : if silent is true, then subtitle would not be displayed. :*/
7848 int
7849 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7850 {
7851         mmplayer_t *player = (mmplayer_t *)hplayer;
7852
7853         MMPLAYER_FENTER();
7854
7855         /* check player handle */
7856         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7857
7858         player->set_mode.subtitle_off = silent;
7859
7860         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7861
7862         MMPLAYER_FLEAVE();
7863
7864         return MM_ERROR_NONE;
7865 }
7866
7867 int
7868 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7869 {
7870         mmplayer_gst_element_t *mainbin = NULL;
7871         mmplayer_gst_element_t *textbin = NULL;
7872         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7873         GstState current_state = GST_STATE_VOID_PENDING;
7874         GstState element_state = GST_STATE_VOID_PENDING;
7875         GstState element_pending_state = GST_STATE_VOID_PENDING;
7876         gint64 time = 0;
7877         GstEvent *event = NULL;
7878         int result = MM_ERROR_NONE;
7879
7880         GstClock *curr_clock = NULL;
7881         GstClockTime base_time, start_time, curr_time;
7882
7883
7884         MMPLAYER_FENTER();
7885
7886         /* check player handle */
7887         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7888                                                                 player->pipeline &&
7889                                                                 player->pipeline->mainbin &&
7890                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7891
7892         mainbin = player->pipeline->mainbin;
7893         textbin = player->pipeline->textbin;
7894
7895         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7896
7897         // sync clock with current pipeline
7898         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7899         curr_time = gst_clock_get_time(curr_clock);
7900
7901         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7902         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7903
7904         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7905                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7906
7907         if (current_state > GST_STATE_READY) {
7908                 // sync state with current pipeline
7909                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7910                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7911                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7912
7913                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7914                 if (GST_STATE_CHANGE_FAILURE == ret) {
7915                         LOGE("fail to state change.");
7916                         result = MM_ERROR_PLAYER_INTERNAL;
7917                         goto ERROR;
7918                 }
7919         }
7920         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7921         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7922
7923         if (curr_clock) {
7924                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7925                 gst_object_unref(curr_clock);
7926         }
7927
7928         // seek to current position
7929         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7930                 result = MM_ERROR_PLAYER_INVALID_STATE;
7931                 LOGE("gst_element_query_position failed, invalid state");
7932                 goto ERROR;
7933         }
7934
7935         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7936         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);
7937         if (event) {
7938                 __mmplayer_gst_send_event_to_sink(player, event);
7939         } else {
7940                 result = MM_ERROR_PLAYER_INTERNAL;
7941                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7942                 goto ERROR;
7943         }
7944
7945         /* sync state with current pipeline */
7946         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7947         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7948         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7949
7950         return MM_ERROR_NONE;
7951
7952 ERROR:
7953         /* release text pipeline resource */
7954         player->textsink_linked = 0;
7955
7956         /* release signal */
7957         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7958
7959         /* release textbin with it's childs */
7960         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7961         MMPLAYER_FREEIF(player->pipeline->textbin);
7962         player->pipeline->textbin = NULL;
7963
7964         /* release subtitle elem */
7965         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7966         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7967
7968         return result;
7969 }
7970
7971 static int
7972 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7973 {
7974         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7975         GstState current_state = GST_STATE_VOID_PENDING;
7976
7977         MMHandleType attrs = 0;
7978         mmplayer_gst_element_t *mainbin = NULL;
7979         mmplayer_gst_element_t *textbin = NULL;
7980
7981         gchar *subtitle_uri = NULL;
7982         int result = MM_ERROR_NONE;
7983         const gchar *charset = NULL;
7984
7985         MMPLAYER_FENTER();
7986
7987         /* check player handle */
7988         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7989                                                                 player->pipeline &&
7990                                                                 player->pipeline->mainbin &&
7991                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7992         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7993
7994         mainbin = player->pipeline->mainbin;
7995         textbin = player->pipeline->textbin;
7996
7997         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7998         if (current_state < GST_STATE_READY) {
7999                 result = MM_ERROR_PLAYER_INVALID_STATE;
8000                 LOGE("Pipeline is not in proper state");
8001                 goto EXIT;
8002         }
8003
8004         attrs = MMPLAYER_GET_ATTRS(player);
8005         if (!attrs) {
8006                 LOGE("cannot get content attribute");
8007                 result = MM_ERROR_PLAYER_INTERNAL;
8008                 goto EXIT;
8009         }
8010
8011         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8012         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8013                 LOGE("subtitle uri is not proper filepath");
8014                 result = MM_ERROR_PLAYER_INVALID_URI;
8015                 goto EXIT;
8016         }
8017
8018         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8019                 LOGE("failed to get storage info of subtitle path");
8020                 result = MM_ERROR_PLAYER_INVALID_URI;
8021                 goto EXIT;
8022         }
8023
8024         LOGD("old subtitle file path is [%s]", subtitle_uri);
8025         LOGD("new subtitle file path is [%s]", filepath);
8026
8027         if (!strcmp(filepath, subtitle_uri)) {
8028                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8029                 goto EXIT;
8030         } else {
8031                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8032                 if (mm_attrs_commit_all(player->attrs)) {
8033                         LOGE("failed to commit.");
8034                         goto EXIT;
8035                 }
8036         }
8037
8038         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8039         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8040         player->subtitle_language_list = NULL;
8041         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8042
8043         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8044         if (ret != GST_STATE_CHANGE_SUCCESS) {
8045                 LOGE("failed to change state of textbin to READY");
8046                 result = MM_ERROR_PLAYER_INTERNAL;
8047                 goto EXIT;
8048         }
8049
8050         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8051         if (ret != GST_STATE_CHANGE_SUCCESS) {
8052                 LOGE("failed to change state of subparse to READY");
8053                 result = MM_ERROR_PLAYER_INTERNAL;
8054                 goto EXIT;
8055         }
8056
8057         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8058         if (ret != GST_STATE_CHANGE_SUCCESS) {
8059                 LOGE("failed to change state of filesrc to READY");
8060                 result = MM_ERROR_PLAYER_INTERNAL;
8061                 goto EXIT;
8062         }
8063
8064         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8065
8066         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8067
8068         charset = util_get_charset(filepath);
8069         if (charset) {
8070                 LOGD("detected charset is %s", charset);
8071                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8072         }
8073
8074         result = _mmplayer_sync_subtitle_pipeline(player);
8075
8076 EXIT:
8077         MMPLAYER_FLEAVE();
8078         return result;
8079 }
8080
8081 /* API to switch between external subtitles */
8082 int
8083 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8084 {
8085         int result = MM_ERROR_NONE;
8086         mmplayer_t *player = (mmplayer_t *)hplayer;
8087         char *path = NULL;
8088
8089         MMPLAYER_FENTER();
8090
8091         /* check player handle */
8092         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8093
8094         /* filepath can be null in idle state */
8095         if (filepath) {
8096                 /* check file path */
8097                 if ((path = strstr(filepath, "file://")))
8098                         result = util_exist_file_path(path + 7);
8099                 else
8100                         result = util_exist_file_path(filepath);
8101
8102                 if (result != MM_ERROR_NONE) {
8103                         LOGE("invalid subtitle path 0x%X", result);
8104                         return result; /* file not found or permission denied */
8105                 }
8106         }
8107
8108         if (!player->pipeline) {
8109                 /* IDLE state */
8110                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8111                 if (mm_attrs_commit_all(player->attrs)) {
8112                         LOGE("failed to commit");       /* subtitle path will not be created */
8113                         return MM_ERROR_PLAYER_INTERNAL;
8114                 }
8115         } else {
8116                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8117                 /* check filepath */
8118                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8119
8120                 if (!__mmplayer_check_subtitle(player)) {
8121                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8122                         if (mm_attrs_commit_all(player->attrs)) {
8123                                 LOGE("failed to commit");
8124                                 return MM_ERROR_PLAYER_INTERNAL;
8125                         }
8126
8127                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8128                                 LOGE("fail to create text pipeline");
8129                                 return MM_ERROR_PLAYER_INTERNAL;
8130                         }
8131
8132                         result = _mmplayer_sync_subtitle_pipeline(player);
8133                 } else {
8134                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8135                 }
8136
8137                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8138                 player->is_external_subtitle_added_now = TRUE;
8139
8140                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8141                 if (!player->subtitle_language_list) {
8142                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8143                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8144                                 LOGW("subtitle language list is not updated yet");
8145                 }
8146                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8147         }
8148
8149         MMPLAYER_FLEAVE();
8150         return result;
8151 }
8152
8153 static int
8154 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8155 {
8156         int result = MM_ERROR_NONE;
8157         gchar *change_pad_name = NULL;
8158         GstPad *sinkpad = NULL;
8159         mmplayer_gst_element_t *mainbin = NULL;
8160         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8161         GstCaps *caps = NULL;
8162         gint total_track_num = 0;
8163
8164         MMPLAYER_FENTER();
8165
8166         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8167                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8168
8169         LOGD("Change Track(%d) to %d", type, index);
8170
8171         mainbin = player->pipeline->mainbin;
8172
8173         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8174                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8175         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8176                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8177         } else {
8178                 /* Changing Video Track is not supported. */
8179                 LOGE("Track Type Error");
8180                 goto EXIT;
8181         }
8182
8183         if (mainbin[elem_idx].gst == NULL) {
8184                 result = MM_ERROR_PLAYER_NO_OP;
8185                 LOGD("Req track doesn't exist");
8186                 goto EXIT;
8187         }
8188
8189         total_track_num = player->selector[type].total_track_num;
8190         if (total_track_num <= 0) {
8191                 result = MM_ERROR_PLAYER_NO_OP;
8192                 LOGD("Language list is not available");
8193                 goto EXIT;
8194         }
8195
8196         if ((index < 0) || (index >= total_track_num)) {
8197                 result = MM_ERROR_INVALID_ARGUMENT;
8198                 LOGD("Not a proper index : %d", index);
8199                 goto EXIT;
8200         }
8201
8202         /*To get the new pad from the selector*/
8203         change_pad_name = g_strdup_printf("sink_%u", index);
8204         if (change_pad_name == NULL) {
8205                 result = MM_ERROR_PLAYER_INTERNAL;
8206                 LOGD("Pad does not exists");
8207                 goto EXIT;
8208         }
8209
8210         LOGD("new active pad name: %s", change_pad_name);
8211
8212         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8213         if (sinkpad == NULL) {
8214                 LOGD("sinkpad is NULL");
8215                 result = MM_ERROR_PLAYER_INTERNAL;
8216                 goto EXIT;
8217         }
8218
8219         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8220         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8221
8222         caps = gst_pad_get_current_caps(sinkpad);
8223         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8224
8225         if (sinkpad)
8226                 gst_object_unref(sinkpad);
8227
8228         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8229                 __mmplayer_set_audio_attrs(player, caps);
8230
8231 EXIT:
8232         MMPLAYER_FREEIF(change_pad_name);
8233         return result;
8234 }
8235
8236 int
8237 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8238 {
8239         int result = MM_ERROR_NONE;
8240         mmplayer_t *player = NULL;
8241         mmplayer_gst_element_t *mainbin = NULL;
8242
8243         gint current_active_index = 0;
8244
8245         GstState current_state = GST_STATE_VOID_PENDING;
8246         GstEvent *event = NULL;
8247         gint64 time = 0;
8248
8249         MMPLAYER_FENTER();
8250
8251         player = (mmplayer_t *)hplayer;
8252         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8253
8254         if (!player->pipeline) {
8255                 LOGE("Track %d pre setting -> %d", type, index);
8256
8257                 player->selector[type].active_pad_index = index;
8258                 goto EXIT;
8259         }
8260
8261         mainbin = player->pipeline->mainbin;
8262
8263         current_active_index = player->selector[type].active_pad_index;
8264
8265         /*If index is same as running index no need to change the pad*/
8266         if (current_active_index == index)
8267                 goto EXIT;
8268
8269         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8270                 result = MM_ERROR_PLAYER_INVALID_STATE;
8271                 goto EXIT;
8272         }
8273
8274         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8275         if (current_state < GST_STATE_PAUSED) {
8276                 result = MM_ERROR_PLAYER_INVALID_STATE;
8277                 LOGW("Pipeline not in porper state");
8278                 goto EXIT;
8279         }
8280
8281         result = __mmplayer_change_selector_pad(player, type, index);
8282         if (result != MM_ERROR_NONE) {
8283                 LOGE("change selector pad error");
8284                 goto EXIT;
8285         }
8286
8287         player->selector[type].active_pad_index = index;
8288
8289         if (current_state == GST_STATE_PLAYING) {
8290                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8291                         (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8292                         GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8293                 if (event) {
8294                         __mmplayer_gst_send_event_to_sink(player, event);
8295                 } else {
8296                         result = MM_ERROR_PLAYER_INTERNAL;
8297                         goto EXIT;
8298                 }
8299         }
8300
8301 EXIT:
8302         return result;
8303 }
8304
8305 int
8306 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8307 {
8308         mmplayer_t *player = (mmplayer_t *)hplayer;
8309
8310         MMPLAYER_FENTER();
8311
8312         /* check player handle */
8313         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8314
8315         *silent = player->set_mode.subtitle_off;
8316
8317         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8318
8319         MMPLAYER_FLEAVE();
8320
8321         return MM_ERROR_NONE;
8322 }
8323
8324 static gboolean
8325 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8326 {
8327         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8328         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8329
8330         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8331         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8332
8333         int idx = 0;
8334
8335         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8336                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8337                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8338                         mmplayer_dump_t *dump_s;
8339                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8340                         if (dump_s == NULL) {
8341                                 LOGE("malloc fail");
8342                                 return FALSE;
8343                         }
8344
8345                         dump_s->dump_element_file = NULL;
8346                         dump_s->dump_pad = NULL;
8347                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8348
8349                         if (dump_s->dump_pad) {
8350                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8351                                 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]);
8352                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8353                                 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);
8354                                 /* add list for removed buffer probe and close FILE */
8355                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8356                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8357                                 return TRUE;
8358                         } else {
8359                                 MMPLAYER_FREEIF(dump_s);
8360                                 LOGE("failed to get %s sink pad added", factory_name);
8361                         }
8362                 }
8363         }
8364         return FALSE;
8365 }
8366
8367 static GstPadProbeReturn
8368 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8369 {
8370         FILE *dump_data = (FILE *)u_data;
8371 //      int written = 0;
8372         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8373         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8374
8375         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8376
8377         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8378
8379 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8380
8381         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8382
8383         gst_buffer_unmap(buffer, &probe_info);
8384
8385         return GST_PAD_PROBE_OK;
8386 }
8387
8388 static void
8389 __mmplayer_release_dump_list(GList *dump_list)
8390 {
8391         GList *d_list = dump_list;
8392
8393         if (!d_list)
8394                 return;
8395
8396         for (; d_list; d_list = g_list_next(d_list)) {
8397                 mmplayer_dump_t *dump_s = d_list->data;
8398                 if (dump_s->dump_pad) {
8399                         if (dump_s->probe_handle_id)
8400                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8401                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8402                 }
8403                 if (dump_s->dump_element_file) {
8404                         fclose(dump_s->dump_element_file);
8405                         dump_s->dump_element_file = NULL;
8406                 }
8407                 MMPLAYER_FREEIF(dump_s);
8408         }
8409         g_list_free(dump_list);
8410         dump_list = NULL;
8411 }
8412
8413 int
8414 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8415 {
8416         mmplayer_t *player = (mmplayer_t *)hplayer;
8417
8418         MMPLAYER_FENTER();
8419
8420         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8421         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8422
8423         *exist = (bool)player->has_closed_caption;
8424
8425         MMPLAYER_FLEAVE();
8426
8427         return MM_ERROR_NONE;
8428 }
8429
8430 void
8431 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8432 {
8433         MMPLAYER_FENTER();
8434         if (buffer) {
8435                 // LOGD("unref internal gst buffer %p", buffer);
8436                 gst_buffer_unref((GstBuffer *)buffer);
8437                 buffer = NULL;
8438         }
8439         MMPLAYER_FLEAVE();
8440 }
8441
8442 int
8443 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8444 {
8445         mmplayer_t *player = (mmplayer_t *)hplayer;
8446
8447         MMPLAYER_FENTER();
8448
8449         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8450         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8451
8452         if (MMPLAYER_IS_STREAMING(player))
8453                 *timeout = (int)player->ini.live_state_change_timeout;
8454         else
8455                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8456
8457         LOGD("timeout = %d", *timeout);
8458
8459         MMPLAYER_FLEAVE();
8460         return MM_ERROR_NONE;
8461 }
8462
8463 int
8464 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8465 {
8466         mmplayer_t *player = (mmplayer_t *)hplayer;
8467
8468         MMPLAYER_FENTER();
8469
8470         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8471         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8472
8473         *num = player->video_num_buffers;
8474         *extra_num = player->video_extra_num_buffers;
8475
8476         LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8477
8478         MMPLAYER_FLEAVE();
8479         return MM_ERROR_NONE;
8480 }
8481
8482 static void
8483 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8484 {
8485         int i = 0;
8486         MMPLAYER_FENTER();
8487         MMPLAYER_RETURN_IF_FAIL(player);
8488
8489         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8490
8491                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8492                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8493                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8494                         player->storage_info[i].id = -1;
8495                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8496
8497                         if (path_type != MMPLAYER_PATH_MAX)
8498                                 break;
8499                 }
8500         }
8501
8502         MMPLAYER_FLEAVE();
8503 }
8504
8505 int
8506 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8507 {
8508         int ret = MM_ERROR_NONE;
8509         mmplayer_t *player = (mmplayer_t *)hplayer;
8510         MMMessageParamType msg_param = {0, };
8511
8512         MMPLAYER_FENTER();
8513         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8514
8515         LOGW("state changed storage %d:%d", id, state);
8516
8517         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8518                 return MM_ERROR_NONE;
8519
8520         /* FIXME: text path should be handled seperately. */
8521         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8522                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8523                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8524                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8525                 LOGW("external storage is removed");
8526
8527                 if (player->msg_posted == FALSE) {
8528                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8529                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8530                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8531                         player->msg_posted = TRUE;
8532                 }
8533
8534                 /* unrealize the player */
8535                 ret = _mmplayer_unrealize(hplayer);
8536                 if (ret != MM_ERROR_NONE)
8537                         LOGE("failed to unrealize");
8538         }
8539
8540         MMPLAYER_FLEAVE();
8541         return ret;
8542 }
8543
8544 int
8545 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8546 {
8547         int ret = MM_ERROR_NONE;
8548         mmplayer_t *player = (mmplayer_t *)hplayer;
8549         int idx = 0, total = 0;
8550         gchar *result = NULL, *tmp = NULL;
8551
8552         MMPLAYER_FENTER();
8553         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8555
8556         total = *num = g_list_length(player->adaptive_info.var_list);
8557         if (total <= 0) {
8558                 LOGW("There is no stream variant info.");
8559                 return ret;
8560         }
8561
8562         result = g_strdup("");
8563         for (idx = 0 ; idx < total ; idx++) {
8564                 stream_variant_t *v_data = NULL;
8565                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8566
8567                 if (v_data) {
8568                         gchar data[64] = {0};
8569                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8570
8571                         tmp = g_strconcat(result, data, NULL);
8572                         g_free(result);
8573                         result = tmp;
8574                 } else {
8575                         LOGW("There is no variant data in %d", idx);
8576                         (*num)--;
8577                 }
8578         }
8579
8580         *var_info = (char *)result;
8581
8582         LOGD("variant info %d:%s", *num, *var_info);
8583         MMPLAYER_FLEAVE();
8584         return ret;
8585 }
8586
8587 int
8588 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8589 {
8590         int ret = MM_ERROR_NONE;
8591         mmplayer_t *player = (mmplayer_t *)hplayer;
8592
8593         MMPLAYER_FENTER();
8594         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595
8596         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8597
8598         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8599         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8600         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8601
8602         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8603                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8604                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8605                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8606
8607                 /* FIXME: seek to current position for applying new variant limitation */
8608         }
8609
8610         MMPLAYER_FLEAVE();
8611         return ret;
8612
8613 }
8614
8615 int
8616 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8617 {
8618         int ret = MM_ERROR_NONE;
8619         mmplayer_t *player = (mmplayer_t *)hplayer;
8620
8621         MMPLAYER_FENTER();
8622         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8623         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8624
8625         *bandwidth = player->adaptive_info.limit.bandwidth;
8626         *width = player->adaptive_info.limit.width;
8627         *height = player->adaptive_info.limit.height;
8628
8629         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8630
8631         MMPLAYER_FLEAVE();
8632         return ret;
8633 }
8634
8635 int
8636 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8637 {
8638         int ret = MM_ERROR_NONE;
8639         mmplayer_t *player = (mmplayer_t *)hplayer;
8640
8641         MMPLAYER_FENTER();
8642         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8643         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8644         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8645
8646         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8647
8648         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8649                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8650         else /* live case */
8651                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8652
8653         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8654
8655         MMPLAYER_FLEAVE();
8656         return ret;
8657 }
8658
8659 int
8660 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8661 {
8662 #define IDX_FIRST_SW_CODEC 0
8663         mmplayer_t *player = (mmplayer_t *)hplayer;
8664         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8665         MMHandleType attrs = 0;
8666
8667         MMPLAYER_FENTER();
8668         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8669
8670         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8671                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8672                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8673
8674         switch (stream_type) {
8675         case MM_PLAYER_STREAM_TYPE_AUDIO:
8676         /* to support audio codec selection, codec info have to be added in ini file as below.
8677            audio codec element hw = xxxx
8678            audio codec element sw = avdec */
8679                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8680                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8681                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8682                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8683                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8684                         return MM_ERROR_PLAYER_NO_OP;
8685                 }
8686         break;
8687         case MM_PLAYER_STREAM_TYPE_VIDEO:
8688         /* to support video codec selection, codec info have to be added in ini file as below.
8689            video codec element hw = omx
8690            video codec element sw = avdec */
8691                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8692                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8693                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8694                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8695                         LOGE("There is no video codec info for codec_type %d", codec_type);
8696                         return MM_ERROR_PLAYER_NO_OP;
8697                 }
8698         break;
8699         default:
8700                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8701                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8702         break;
8703         }
8704
8705         LOGD("update %s codec_type to %d", attr_name, codec_type);
8706
8707         attrs = MMPLAYER_GET_ATTRS(player);
8708         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8709
8710         if (mm_attrs_commit_all(player->attrs)) {
8711                 LOGE("failed to commit codec_type attributes");
8712                 return MM_ERROR_PLAYER_INTERNAL;
8713         }
8714
8715         MMPLAYER_FLEAVE();
8716         return MM_ERROR_NONE;
8717 }
8718
8719 int
8720 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8721 {
8722         mmplayer_t *player = (mmplayer_t *)hplayer;
8723         GstElement *rg_vol_element = NULL;
8724
8725         MMPLAYER_FENTER();
8726
8727         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8728
8729         player->sound.rg_enable = enabled;
8730
8731         /* just hold rgvolume enable value if pipeline is not ready */
8732         if (!player->pipeline || !player->pipeline->audiobin) {
8733                 LOGD("pipeline is not ready. holding rgvolume enable value");
8734                 return MM_ERROR_NONE;
8735         }
8736
8737         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8738
8739         if (!rg_vol_element) {
8740                 LOGD("rgvolume element is not created");
8741                 return MM_ERROR_PLAYER_INTERNAL;
8742         }
8743
8744         if (enabled)
8745                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8746         else
8747                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8748
8749         MMPLAYER_FLEAVE();
8750
8751         return MM_ERROR_NONE;
8752 }
8753
8754 int
8755 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8756 {
8757         mmplayer_t *player = (mmplayer_t *)hplayer;
8758         GstElement *rg_vol_element = NULL;
8759         gboolean enable = FALSE;
8760
8761         MMPLAYER_FENTER();
8762
8763         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8764         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8765
8766         /* just hold enable_rg value if pipeline is not ready */
8767         if (!player->pipeline || !player->pipeline->audiobin) {
8768                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8769                 *enabled = player->sound.rg_enable;
8770                 return MM_ERROR_NONE;
8771         }
8772
8773         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8774
8775         if (!rg_vol_element) {
8776                 LOGD("rgvolume element is not created");
8777                 return MM_ERROR_PLAYER_INTERNAL;
8778         }
8779
8780         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8781         *enabled = (bool)enable;
8782
8783         MMPLAYER_FLEAVE();
8784
8785         return MM_ERROR_NONE;
8786 }
8787
8788 int
8789 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8790 {
8791         mmplayer_t *player = (mmplayer_t *)hplayer;
8792         MMHandleType attrs = 0;
8793         void *handle = NULL;
8794         int ret = MM_ERROR_NONE;
8795
8796         MMPLAYER_FENTER();
8797
8798         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8799
8800         attrs = MMPLAYER_GET_ATTRS(player);
8801         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8802
8803         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8804         if (!handle) {
8805                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8806                 return MM_ERROR_PLAYER_INTERNAL;
8807         }
8808
8809         player->video_roi.scale_x = scale_x;
8810         player->video_roi.scale_y = scale_y;
8811         player->video_roi.scale_width = scale_width;
8812         player->video_roi.scale_height = scale_height;
8813
8814         /* check video sinkbin is created */
8815         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8816                 return MM_ERROR_NONE;
8817
8818         if (!gst_video_overlay_set_video_roi_area(
8819                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8820                 scale_x, scale_y, scale_width, scale_height))
8821                 ret = MM_ERROR_PLAYER_INTERNAL;
8822         else
8823                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8824                         scale_x, scale_y, scale_width, scale_height);
8825
8826         MMPLAYER_FLEAVE();
8827
8828         return ret;
8829 }
8830
8831 int
8832 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8833 {
8834         mmplayer_t *player = (mmplayer_t *)hplayer;
8835         int ret = MM_ERROR_NONE;
8836
8837         MMPLAYER_FENTER();
8838
8839         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8840         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8841
8842         *scale_x = player->video_roi.scale_x;
8843         *scale_y = player->video_roi.scale_y;
8844         *scale_width = player->video_roi.scale_width;
8845         *scale_height = player->video_roi.scale_height;
8846
8847         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8848                 *scale_x, *scale_y, *scale_width, *scale_height);
8849
8850         return ret;
8851 }
8852
8853 static gboolean
8854 __mmplayer_update_duration_value(mmplayer_t *player)
8855 {
8856         gboolean ret = FALSE;
8857         gint64 dur_nsec = 0;
8858         LOGD("try to update duration");
8859
8860         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8861                 player->duration = dur_nsec;
8862                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8863                 ret = TRUE;
8864         }
8865
8866         if (player->duration < 0) {
8867                 LOGW("duration is Non-Initialized !!!");
8868                 player->duration = 0;
8869         }
8870
8871         /* update streaming service type */
8872         player->streaming_type =  __mmplayer_get_stream_service_type(player);
8873
8874         /* check duration is OK */
8875         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8876                 /* FIXIT : find another way to get duration here. */
8877                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8878
8879         return ret;
8880 }
8881
8882 static gboolean
8883 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8884 {
8885         /* update audio params
8886         NOTE : We need original audio params and it can be only obtained from src pad of audio
8887         decoder. Below code only valid when we are not using 'resampler' just before
8888         'audioconverter'. */
8889         GstCaps *caps_a = NULL;
8890         GstPad *pad = NULL;
8891         gint samplerate = 0, channels = 0;
8892         GstStructure *p = NULL;
8893
8894         LOGD("try to update audio attrs");
8895
8896         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8897         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8898
8899         pad = gst_element_get_static_pad(
8900                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8901
8902         if (!pad) {
8903                 LOGW("failed to get pad from audiosink");
8904                 return FALSE;
8905         }
8906
8907         caps_a = gst_pad_get_current_caps(pad);
8908         if (!caps_a) {
8909                 LOGW("not ready to get audio caps");
8910                 gst_object_unref(pad);
8911                 return FALSE;
8912         }
8913
8914         p = gst_caps_get_structure(caps_a, 0);
8915
8916         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8917
8918         gst_structure_get_int(p, "rate", &samplerate);
8919         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8920
8921         gst_structure_get_int(p, "channels", &channels);
8922         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8923
8924         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8925
8926         gst_caps_unref(caps_a);
8927         gst_object_unref(pad);
8928
8929         return TRUE;
8930 }
8931
8932 static gboolean
8933 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8934 {
8935         LOGD("try to update video attrs");
8936
8937         GstCaps *caps_v = NULL;
8938         GstPad *pad = NULL;
8939         gint tmpNu, tmpDe;
8940         gint width, height;
8941         GstStructure *p = NULL;
8942
8943         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8944         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8945
8946         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8947         if (!pad) {
8948                 LOGD("no videosink sink pad");
8949                 return FALSE;
8950         }
8951
8952         caps_v = gst_pad_get_current_caps(pad);
8953         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8954         if (!caps_v && player->v_stream_caps) {
8955                 caps_v = player->v_stream_caps;
8956                 gst_caps_ref(caps_v);
8957         }
8958
8959         if (!caps_v) {
8960                 LOGD("no negitiated caps from videosink");
8961                 gst_object_unref(pad);
8962                 return FALSE;
8963         }
8964
8965         p = gst_caps_get_structure(caps_v, 0);
8966         gst_structure_get_int(p, "width", &width);
8967         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8968
8969         gst_structure_get_int(p, "height", &height);
8970         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8971
8972         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8973
8974         SECURE_LOGD("width : %d     height : %d", width, height);
8975
8976         gst_caps_unref(caps_v);
8977         gst_object_unref(pad);
8978
8979         if (tmpDe > 0) {
8980                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8981                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8982         }
8983
8984         return TRUE;
8985 }
8986
8987 static gboolean
8988 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8989 {
8990         gboolean ret = FALSE;
8991         guint64 data_size = 0;
8992         gchar *path = NULL;
8993         struct stat sb;
8994
8995         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8996         if (!player->duration)
8997                 return FALSE;
8998
8999         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9000                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9001                 if (stat(path, &sb) == 0)
9002                         data_size = (guint64)sb.st_size;
9003
9004         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9005                 data_size = player->http_content_size;
9006         }
9007
9008         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9009
9010         if (data_size) {
9011                 guint64 bitrate = 0;
9012                 guint64 msec_dur = 0;
9013
9014                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9015                 if (msec_dur > 0) {
9016                         bitrate = data_size * 8 * 1000 / msec_dur;
9017                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9018                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9019
9020                         ret = TRUE;
9021                 } else {
9022                         LOGD("player duration is less than 0");
9023                 }
9024         }
9025
9026         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9027                 if (player->total_bitrate) {
9028                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9029                         ret = TRUE;
9030                 }
9031         }
9032
9033         return ret;
9034 }
9035
9036 static void
9037 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9038 {
9039         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9040         data->uri_type = uri_type;
9041 }
9042
9043 static int
9044 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9045 {
9046         int ret = MM_ERROR_PLAYER_INVALID_URI;
9047         int mem_size = 0;
9048         char *buffer = NULL;
9049         char *seperator = strchr(path, ',');
9050         char ext[100] = {0,}, size[100] = {0,};
9051
9052         if (seperator) {
9053                 if ((buffer = strstr(path, "ext="))) {
9054                         buffer += strlen("ext=");
9055
9056                         if (strlen(buffer)) {
9057                                 strncpy(ext, buffer, 99);
9058
9059                                 if ((seperator = strchr(ext, ','))
9060                                         || (seperator = strchr(ext, ' '))
9061                                         || (seperator = strchr(ext, '\0'))) {
9062                                         seperator[0] = '\0';
9063                                 }
9064                         }
9065                 }
9066
9067                 if ((buffer = strstr(path, "size="))) {
9068                         buffer += strlen("size=");
9069
9070                         if (strlen(buffer) > 0) {
9071                                 strncpy(size, buffer, 99);
9072
9073                                 if ((seperator = strchr(size, ','))
9074                                         || (seperator = strchr(size, ' '))
9075                                         || (seperator = strchr(size, '\0'))) {
9076                                         seperator[0] = '\0';
9077                                 }
9078
9079                                 mem_size = atoi(size);
9080                         }
9081                 }
9082         }
9083
9084         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9085
9086         if (mem_size && param) {
9087                 if (data->input_mem.buf)
9088                         free(data->input_mem.buf);
9089                 data->input_mem.buf = malloc(mem_size);
9090
9091                 if (data->input_mem.buf) {
9092                         memcpy(data->input_mem.buf, param, mem_size);
9093                         data->input_mem.len = mem_size;
9094                         ret = MM_ERROR_NONE;
9095                 } else {
9096                         LOGE("failed to alloc mem %d", mem_size);
9097                         ret = MM_ERROR_PLAYER_INTERNAL;
9098                 }
9099
9100                 data->input_mem.offset = 0;
9101                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9102         }
9103
9104         return ret;
9105 }
9106
9107 static int
9108 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9109 {
9110         gchar *location = NULL;
9111         GError *err = NULL;
9112         char *path = NULL;
9113         int ret = MM_ERROR_NONE;
9114
9115         if ((path = strstr(uri, "file://"))) {
9116                 location = g_filename_from_uri(uri, NULL, &err);
9117                 if (!location || (err != NULL)) {
9118                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9119                                 (err != NULL) ? err->message : "unknown error");
9120                         if (err)
9121                                 g_error_free(err);
9122
9123                         MMPLAYER_FREEIF(location);
9124
9125                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9126                         return MM_ERROR_PLAYER_INVALID_URI;
9127                 }
9128                 LOGD("path from uri: %s", location);
9129         }
9130
9131         path = (location != NULL) ? (location) : ((char *)uri);
9132
9133
9134         ret = util_exist_file_path(path);
9135
9136         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9137         if (ret == MM_ERROR_NONE) {
9138                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9139                 if (util_is_sdp_file(path)) {
9140                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9141                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9142                 } else {
9143                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9144                 }
9145         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9146                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9147         } else {
9148                 LOGE("invalid uri, could not play..");
9149                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9150         }
9151
9152         MMPLAYER_FREEIF(location);
9153
9154         return ret;
9155 }
9156
9157 static mmplayer_video_decoded_data_info_t *
9158 __mmplayer_create_stream_from_pad(GstPad *pad)
9159 {
9160         GstCaps *caps = NULL;
9161         GstStructure *structure = NULL;
9162         unsigned int fourcc = 0;
9163         const gchar *string_format = NULL;
9164         mmplayer_video_decoded_data_info_t *stream = NULL;
9165         gint width, height;
9166         MMPixelFormatType format;
9167         GstVideoInfo info;
9168
9169         caps = gst_pad_get_current_caps(pad);
9170         if (!caps) {
9171                 LOGE("Caps is NULL.");
9172                 return NULL;
9173         }
9174
9175         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9176         structure = gst_caps_get_structure(caps, 0);
9177         gst_structure_get_int(structure, "width", &width);
9178         gst_structure_get_int(structure, "height", &height);
9179         string_format = gst_structure_get_string(structure, "format");
9180
9181         if (string_format)
9182                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9183         format = util_get_pixtype(fourcc);
9184         gst_video_info_from_caps(&info, caps);
9185         gst_caps_unref(caps);
9186
9187         /* moved here */
9188         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9189                 LOGE("Wrong condition!!");
9190                 return NULL;
9191         }
9192
9193         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9194         if (!stream) {
9195                 LOGE("failed to alloc mem for video data");
9196                 return NULL;
9197         }
9198
9199         stream->width = width;
9200         stream->height = height;
9201         stream->format = format;
9202         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9203
9204         return stream;
9205 }
9206
9207 static void
9208 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9209 {
9210         unsigned int pitch = 0;
9211         unsigned int size = 0;
9212         int index = 0;
9213         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9214         tbm_bo bo = NULL;
9215
9216         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9217                 bo = gst_tizen_memory_get_bos(mem, index);
9218                 if (bo)
9219                         stream->bo[index] = tbm_bo_ref(bo);
9220                 else
9221                         LOGE("failed to get bo for index %d", index);
9222         }
9223
9224         for (index = 0; index < stream->plane_num; index++) {
9225                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9226                 stream->stride[index] = pitch;
9227                 if (pitch)
9228                         stream->elevation[index] = size / pitch;
9229                 else
9230                         stream->elevation[index] = stream->height;
9231         }
9232 }
9233
9234 static gboolean
9235 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9236 {
9237         if (stream->format == MM_PIXEL_FORMAT_I420) {
9238                 int ret = TBM_SURFACE_ERROR_NONE;
9239                 tbm_surface_h surface;
9240                 tbm_surface_info_s info;
9241
9242                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9243
9244                 ret = tbm_surface_get_info(surface, &info);
9245                 if (ret != TBM_SURFACE_ERROR_NONE) {
9246                         tbm_surface_destroy(surface);
9247                         return FALSE;
9248                 }
9249
9250                 tbm_surface_destroy(surface);
9251                 stream->stride[0] = info.planes[0].stride;
9252                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9253                 stream->stride[1] = info.planes[1].stride;
9254                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9255                 stream->stride[2] = info.planes[2].stride;
9256                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9257                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9258         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9259                 stream->stride[0] = stream->width * 4;
9260                 stream->elevation[0] = stream->height;
9261                 stream->bo_size = stream->stride[0] * stream->height;
9262         } else {
9263                 LOGE("Not support format %d", stream->format);
9264                 return FALSE;
9265         }
9266
9267         return TRUE;
9268 }
9269
9270 static gboolean
9271 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9272 {
9273         tbm_bo_handle thandle;
9274         gboolean is_mapped;
9275         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9276         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9277         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9278         int i = 0;
9279         int j = 0;
9280         int k = 0;
9281         unsigned char *src = NULL;
9282         unsigned char *dest = NULL;
9283         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9284
9285         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9286         if (!is_mapped) {
9287                 LOGE("fail to gst_memory_map");
9288                 return FALSE;
9289         }
9290
9291         if (!mapinfo.data) {
9292                 LOGE("data pointer is wrong");
9293                 goto ERROR;
9294         }
9295
9296         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9297         if (!stream->bo[0]) {
9298                 LOGE("Fail to tbm_bo_alloc!!");
9299                 goto ERROR;
9300         }
9301
9302         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9303         if (!thandle.ptr) {
9304                 LOGE("thandle pointer is wrong");
9305                 goto ERROR;
9306         }
9307
9308         if (stream->format == MM_PIXEL_FORMAT_I420) {
9309                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9310                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9311                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9312                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9313
9314                 dest_offset[0] = 0;
9315                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9316                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9317
9318                 for (i = 0; i < 3; i++) {
9319                         src = mapinfo.data + src_offset[i];
9320                         dest = thandle.ptr + dest_offset[i];
9321
9322                         if (i > 0)
9323                                 k = 1;
9324
9325                         for (j = 0; j < stream->height >> k; j++) {
9326                                 memcpy(dest, src, stream->width>>k);
9327                                 src += src_stride[i];
9328                                 dest += stream->stride[i];
9329                         }
9330                 }
9331         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9332                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9333         } else {
9334                 LOGE("Not support format %d", stream->format);
9335                 goto ERROR;
9336         }
9337
9338         tbm_bo_unmap(stream->bo[0]);
9339         gst_memory_unmap(mem, &mapinfo);
9340
9341         return TRUE;
9342
9343 ERROR:
9344         if (stream->bo[0])
9345                 tbm_bo_unmap(stream->bo[0]);
9346
9347         if (is_mapped)
9348                 gst_memory_unmap(mem, &mapinfo);
9349
9350         return FALSE;
9351 }
9352
9353 static void
9354 __mmplayer_set_pause_state(mmplayer_t *player)
9355 {
9356         if (player->sent_bos)
9357                 return;
9358
9359         /* rtsp case, get content attrs by GstMessage */
9360         if (MMPLAYER_IS_RTSP_STREAMING(player))
9361                 return;
9362
9363         /* it's first time to update all content attrs. */
9364         __mmplayer_update_content_attrs(player, ATTR_ALL);
9365 }
9366
9367 static void
9368 __mmplayer_set_playing_state(mmplayer_t *player)
9369 {
9370         gchar *audio_codec = NULL;
9371
9372         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9373                 /* initialize because auto resume is done well. */
9374                 player->resumed_by_rewind = FALSE;
9375                 player->playback_rate = 1.0;
9376         }
9377
9378         if (player->sent_bos)
9379                 return;
9380
9381         /* try to get content metadata */
9382
9383         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9384          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9385          * legacy mmfw-player api
9386          */
9387         __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9388
9389         if ((player->cmd == MMPLAYER_COMMAND_START)
9390                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9391                 __mmplayer_handle_missed_plugin(player);
9392         }
9393
9394         /* check audio codec field is set or not
9395          * we can get it from typefinder or codec's caps.
9396          */
9397         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9398
9399         /* The codec format can't be sent for audio only case like amr, mid etc.
9400          * Because, parser don't make related TAG.
9401          * So, if it's not set yet, fill it with found data.
9402          */
9403         if (!audio_codec) {
9404                 if (g_strrstr(player->type, "audio/midi"))
9405                         audio_codec = "MIDI";
9406                 else if (g_strrstr(player->type, "audio/x-amr"))
9407                         audio_codec = "AMR";
9408                 else if (g_strrstr(player->type, "audio/mpeg")
9409                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9410                         audio_codec = "AAC";
9411                 else
9412                         audio_codec = "unknown";
9413
9414                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9415
9416                 if (mm_attrs_commit_all(player->attrs))
9417                         LOGE("failed to update attributes");
9418
9419                 LOGD("set audio codec type with caps");
9420         }
9421
9422         return;
9423 }