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