Merge "[0.6.150] add unittest cases" 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                 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2689
2690                 /* audio effect element. if audio effect is enabled */
2691                 if ((strcmp(player->ini.audioeffect_element, ""))
2692                         && (channels <= 2)
2693                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2694                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2695
2696                         LOGD("audio effect config. bypass = %d, effect type  = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2697
2698                         if ((!player->bypass_audio_effect)
2699                                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2700                                 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2701                                         if (!_mmplayer_audio_effect_custom_apply(player))
2702                                                 LOGI("apply audio effect(custom) setting success");
2703                                 }
2704                         }
2705
2706                         if ((strcmp(player->ini.audioeffect_element_custom, ""))
2707                                 && (player->set_mode.rich_audio))
2708                                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2709                 }
2710
2711                 /* create audio sink */
2712                 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2713                                 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2714                                 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2715
2716                 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2717                 if (player->is_360_feature_enabled &&
2718                         player->is_content_spherical &&
2719                         channels == 4 &&
2720                         player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2721                         player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2722                         player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2723
2724                         strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2725
2726                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2727
2728                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2729                         acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2730                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2731                         gst_caps_unref(acaps);
2732
2733                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2734
2735                         player->is_openal_plugin_used = TRUE;
2736                 } else {
2737                         if (player->is_360_feature_enabled && player->is_content_spherical)
2738                                 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2739                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2740                 }
2741
2742                 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2743                         (player->videodec_linked && player->ini.use_system_clock)) {
2744                         LOGD("system clock will be used.");
2745                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
2746                 }
2747
2748                 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2749                         __mmplayer_gst_set_pulsesink_property(player, attrs);
2750                 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2751                         __mmplayer_gst_set_openalsink_property(player);
2752
2753                 /* qos on */
2754                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
2755                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2756
2757                 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2758                 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2759                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2760                 gst_object_unref(GST_OBJECT(sink_pad));
2761
2762                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2763         }
2764
2765         *bucket = element_bucket;
2766
2767         MMPLAYER_FLEAVE();
2768         return MM_ERROR_NONE;
2769
2770 ERROR:
2771         g_list_free(element_bucket);
2772
2773         *bucket = NULL;
2774         MMPLAYER_FLEAVE();
2775         return MM_ERROR_PLAYER_INTERNAL;
2776 }
2777
2778 static int
2779 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2780 {
2781         MMPlayerGstElement *first_element = NULL;
2782         MMPlayerGstElement *audiobin = NULL;
2783         GstPad *pad = NULL;
2784         GstPad *ghostpad = NULL;
2785         GList *element_bucket = NULL;
2786         int i = 0;
2787
2788         MMPLAYER_FENTER();
2789         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2790
2791         /* alloc handles */
2792         audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2793         if (!audiobin) {
2794                 LOGE("failed to allocate memory for audiobin");
2795                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2796         }
2797
2798         /* create bin */
2799         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2800         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2801         if (!audiobin[MMPLAYER_A_BIN].gst) {
2802                 LOGE("failed to create audiobin");
2803                 goto ERROR;
2804         }
2805
2806         /* take it */
2807         player->pipeline->audiobin = audiobin;
2808
2809         /* create audio filters and audiosink */
2810         if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2811                 goto ERROR;
2812
2813         /* adding created elements to bin */
2814         LOGD("adding created elements to bin");
2815         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2816                 goto ERROR;
2817
2818         /* linking elements in the bucket by added order. */
2819         LOGD("Linking elements in the bucket by added order.");
2820         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2821                 goto ERROR;
2822
2823         /* get first element's sinkpad for creating ghostpad */
2824         first_element = (MMPlayerGstElement *)element_bucket->data;
2825         if (!first_element) {
2826                 LOGE("failed to get first elem");
2827                 goto ERROR;
2828         }
2829
2830         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2831         if (!pad) {
2832                 LOGE("failed to get pad from first element of audiobin");
2833                 goto ERROR;
2834         }
2835
2836         ghostpad = gst_ghost_pad_new("sink", pad);
2837         if (!ghostpad) {
2838                 LOGE("failed to create ghostpad");
2839                 goto ERROR;
2840         }
2841
2842         if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2843                 LOGE("failed to add ghostpad to audiobin");
2844                 goto ERROR;
2845         }
2846
2847         gst_object_unref(pad);
2848
2849         g_list_free(element_bucket);
2850         MMPLAYER_FLEAVE();
2851
2852         return MM_ERROR_NONE;
2853
2854 ERROR:
2855         LOGD("ERROR : releasing audiobin");
2856
2857         if (pad)
2858                 gst_object_unref(GST_OBJECT(pad));
2859
2860         if (ghostpad)
2861                 gst_object_unref(GST_OBJECT(ghostpad));
2862
2863         if (element_bucket)
2864                 g_list_free(element_bucket);
2865
2866         /* release element which are not added to bin */
2867         for (i = 1; i < MMPLAYER_A_NUM; i++) {
2868                 /* NOTE : skip bin */
2869                 if (audiobin[i].gst) {
2870                         GstObject* parent = NULL;
2871                         parent = gst_element_get_parent(audiobin[i].gst);
2872
2873                         if (!parent) {
2874                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2875                                 audiobin[i].gst = NULL;
2876                         } else
2877                                 gst_object_unref(GST_OBJECT(parent));
2878                 }
2879         }
2880
2881         /* release audiobin with it's childs */
2882         if (audiobin[MMPLAYER_A_BIN].gst)
2883                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2884
2885         MMPLAYER_FREEIF(audiobin);
2886
2887         player->pipeline->audiobin = NULL;
2888
2889         return MM_ERROR_PLAYER_INTERNAL;
2890 }
2891
2892 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2893 {
2894         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2895 }
2896
2897 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2898 {
2899         int ret = MM_ERROR_NONE;
2900         GList *l = NULL;
2901         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2902         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2903
2904         MMPLAYER_VIDEO_BO_LOCK(player);
2905
2906         if (player->video_bo_list) {
2907                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2908                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2909                         if (tmp && tmp->bo == bo) {
2910                                 tmp->used = FALSE;
2911                                 LOGD("release bo %p", bo);
2912                                 tbm_bo_unref(tmp->bo);
2913                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
2914                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
2915                                 return ret;
2916                         }
2917                 }
2918         } else {
2919                 /* hw codec is running or the list was reset for DRC. */
2920                 LOGW("there is no bo list.");
2921         }
2922         MMPLAYER_VIDEO_BO_UNLOCK(player);
2923
2924         LOGW("failed to find bo %p", bo);
2925         return ret;
2926 }
2927
2928 static void
2929 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2930 {
2931         GList *l = NULL;
2932
2933         MMPLAYER_FENTER();
2934         MMPLAYER_RETURN_IF_FAIL(player);
2935
2936         MMPLAYER_VIDEO_BO_LOCK(player);
2937         if (player->video_bo_list) {
2938                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2939                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2940                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2941                         if (tmp) {
2942                                 if (tmp->bo)
2943                                         tbm_bo_unref(tmp->bo);
2944                                 g_free(tmp);
2945                         }
2946                 }
2947                 g_list_free(player->video_bo_list);
2948                 player->video_bo_list = NULL;
2949         }
2950         player->video_bo_size = 0;
2951         MMPLAYER_VIDEO_BO_UNLOCK(player);
2952
2953         MMPLAYER_FLEAVE();
2954         return;
2955 }
2956
2957 static void*
2958 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2959 {
2960         GList *l = NULL;
2961         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2962         gboolean ret = TRUE;
2963
2964         /* check DRC, if it is, destroy the prev bo list to create again */
2965         if (player->video_bo_size != size) {
2966                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2967                 __mmplayer_video_stream_destroy_bo_list(player);
2968                 player->video_bo_size = size;
2969         }
2970
2971         MMPLAYER_VIDEO_BO_LOCK(player);
2972
2973         if ((!player->video_bo_list) ||
2974                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2975
2976                 /* create bo list */
2977                 int idx = 0;
2978                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2979
2980                 if (player->video_bo_list) {
2981                         /* if bo list did not created all, try it again. */
2982                         idx = g_list_length(player->video_bo_list);
2983                         LOGD("bo list exist(len: %d)", idx);
2984                 }
2985
2986                 for (; idx < player->ini.num_of_video_bo; idx++) {
2987                         mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
2988                         if (!bo_info) {
2989                                 LOGE("Fail to alloc bo_info.");
2990                                 break;
2991                         }
2992                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2993                         if (!bo_info->bo) {
2994                                 LOGE("Fail to tbm_bo_alloc.");
2995                                 g_free(bo_info);
2996                                 break;
2997                         }
2998                         bo_info->used = FALSE;
2999                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3000                 }
3001
3002                 /* update video num buffers */
3003                 player->video_num_buffers = idx;
3004                 if (idx == player->ini.num_of_video_bo)
3005                         player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3006
3007                 if (idx == 0) {
3008                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3009                         return NULL;
3010                 }
3011
3012                 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3013         }
3014
3015         while (TRUE) {
3016                 /* get bo from list*/
3017                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3018                         mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3019                         if (tmp && (tmp->used == FALSE)) {
3020                                 LOGD("found bo %p to use", tmp->bo);
3021                                 tmp->used = TRUE;
3022                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3023                                 return tbm_bo_ref(tmp->bo);
3024                         }
3025                 }
3026                 if (!ret) {
3027                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3028                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3029                         return NULL;
3030                 }
3031
3032                 if (player->ini.video_bo_timeout <= 0) {
3033                         MMPLAYER_VIDEO_BO_WAIT(player);
3034                 } else {
3035                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3036                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3037                 }
3038                 continue;
3039         }
3040 }
3041
3042 static void
3043 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3044 {
3045         mm_player_t* player = (mm_player_t*)data;
3046         MMPLAYER_FENTER();
3047         MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3048
3049         /* send prerolled pkt */
3050         player->video_stream_prerolled = FALSE;
3051
3052         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3053
3054         /* not to send prerolled pkt again */
3055         player->video_stream_prerolled = TRUE;
3056 }
3057
3058 static void
3059 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3060 {
3061         mm_player_t* player = (mm_player_t*)data;
3062         MMPlayerVideoStreamDataType *stream = NULL;
3063         GstMemory *mem = NULL;
3064
3065         MMPLAYER_FENTER();
3066         MMPLAYER_RETURN_IF_FAIL(player);
3067         MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3068
3069         if (player->video_stream_prerolled) {
3070                 player->video_stream_prerolled = FALSE;
3071                 LOGD("skip the prerolled pkt not to send it again");
3072                 return;
3073         }
3074
3075         /* clear stream data structure */
3076         stream = __mmplayer_create_stream_from_pad(pad);
3077         if (!stream) {
3078                 LOGE("failed to alloc stream");
3079                 return;
3080         }
3081
3082         __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3083
3084         /* set size and timestamp */
3085         mem = gst_buffer_peek_memory(buffer, 0);
3086         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3087         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3088
3089         /* check zero-copy */
3090         if (player->set_mode.video_zc &&
3091                 player->set_mode.media_packet_video_stream &&
3092                 gst_is_tizen_memory(mem)) {
3093                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3094                 stream->internal_buffer = gst_buffer_ref(buffer);
3095         } else { /* sw codec */
3096                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3097                         goto ERROR;
3098
3099                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3100                         goto ERROR;
3101         }
3102
3103         if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3104                 LOGE("failed to send video stream data.");
3105                 goto ERROR;
3106         }
3107
3108         return;
3109
3110 ERROR:
3111         LOGE("release video stream resource.");
3112         if (gst_is_tizen_memory(mem)) {
3113                 int i = 0;
3114                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3115                         if (stream->bo[i])
3116                                 tbm_bo_unref(stream->bo[i]);
3117                 }
3118
3119                 /* unref gst buffer */
3120                 if (stream->internal_buffer)
3121                         gst_buffer_unref(stream->internal_buffer);
3122         } else {
3123                 if (stream->bo[0])
3124                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3125         }
3126         g_free(stream);
3127         return;
3128 }
3129
3130 static void
3131 __mmplayer_gst_set_video360_property(mm_player_t *player)
3132 {
3133         MMPlayerGstElement *videobin = NULL;
3134
3135         MMPLAYER_FENTER();
3136         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3137
3138         videobin = player->pipeline->videobin;
3139
3140         /* Set spatial media metadata and/or user settings to the element.
3141          * */
3142         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3143                         "projection-type", player->video360_metadata.projection_type, NULL);
3144
3145         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3146                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3147
3148         if (player->video360_metadata.full_pano_width_pixels &&
3149                         player->video360_metadata.full_pano_height_pixels &&
3150                         player->video360_metadata.cropped_area_image_width &&
3151                         player->video360_metadata.cropped_area_image_height) {
3152                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3153                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3154                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3155                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3156                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3157                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3158                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3159                                 NULL);
3160         }
3161
3162         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3163                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3164                                 "horizontal-fov", player->video360_horizontal_fov,
3165                                 "vertical-fov", player->video360_vertical_fov, NULL);
3166         }
3167
3168         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3169                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3170                                 "zoom", 1.0f / player->video360_zoom, NULL);
3171         }
3172
3173         if (player->video360_yaw_radians <= M_PI &&
3174                         player->video360_yaw_radians >= -M_PI &&
3175                         player->video360_pitch_radians <= M_PI_2 &&
3176                         player->video360_pitch_radians >= -M_PI_2) {
3177                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3178                                 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3179                                 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3180         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3181                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3182                                 "pose-yaw", player->video360_metadata.init_view_heading,
3183                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3184         }
3185
3186         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3187                         "passthrough", !player->is_video360_enabled, NULL);
3188
3189
3190         MMPLAYER_FLEAVE();
3191 }
3192
3193 static int
3194 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3195 {
3196         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3197         GList *element_bucket = NULL;
3198
3199         MMPLAYER_FENTER();
3200         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3201
3202         /* create video360 filter */
3203         if (player->is_360_feature_enabled && player->is_content_spherical) {
3204                 LOGD("create video360 element");
3205                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3206                 __mmplayer_gst_set_video360_property(player);
3207                 goto EXIT;
3208         }
3209
3210         if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3211                 LOGD("skip creating the videoconv and rotator");
3212                 return MM_ERROR_NONE;
3213         }
3214
3215         /* in case of sw codec & overlay surface type, except 360 playback.
3216          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3217         LOGD("create video converter: %s", video_csc);
3218         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3219
3220         /* set video rotator */
3221         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3222
3223 EXIT:
3224         *bucket = element_bucket;
3225         MMPLAYER_FLEAVE();
3226         return MM_ERROR_NONE;
3227
3228 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3229         g_list_free(element_bucket);
3230
3231         *bucket = NULL;
3232         MMPLAYER_FLEAVE();
3233         return MM_ERROR_PLAYER_INTERNAL;
3234 }
3235
3236 static gchar*
3237 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3238 {
3239         gchar *factory_name = NULL;
3240
3241         switch (surface_type) {
3242         case MM_DISPLAY_SURFACE_OVERLAY:
3243                 if (strlen(player->ini.videosink_element_overlay) > 0)
3244                         factory_name = player->ini.videosink_element_overlay;
3245                 break;
3246         case MM_DISPLAY_SURFACE_REMOTE:
3247         case MM_DISPLAY_SURFACE_NULL:
3248                 if (strlen(player->ini.videosink_element_fake) > 0)
3249                         factory_name = player->ini.videosink_element_fake;
3250                 break;
3251         default:
3252                 LOGE("unidentified surface type");
3253                 break;
3254         }
3255
3256         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3257         return factory_name;
3258 }
3259
3260 static int
3261 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3262 {
3263         gchar *factory_name = NULL;
3264         MMPlayerGstElement *videobin = NULL;
3265         MMHandleType attrs;
3266         int gapless = 0;
3267
3268         MMPLAYER_FENTER();
3269         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3270
3271         videobin = player->pipeline->videobin;
3272         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3273
3274         attrs = MMPLAYER_GET_ATTRS(player);
3275         if (!attrs) {
3276                 LOGE("cannot get content attribute");
3277                 return MM_ERROR_PLAYER_INTERNAL;
3278         }
3279
3280         LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3281         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3282                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3283                 if (!use_tbm) {
3284                         /* support shard memory with S/W codec on HawkP */
3285                         if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3286                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3287                                         "use-tbm", use_tbm, NULL);
3288                         }
3289                 }
3290         } else {
3291                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3292                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3293         }
3294
3295         mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3296         if (gapless > 0) {
3297                 LOGD("disable last-sample");
3298                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3299         }
3300
3301         if (player->set_mode.media_packet_video_stream) {
3302                 int enable = 0;
3303                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3304                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3305                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3306
3307                 __mmplayer_add_signal_connection(player,
3308                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3309                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3310                                                                 "handoff",
3311                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3312                                                                 (gpointer)player);
3313
3314                 __mmplayer_add_signal_connection(player,
3315                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3316                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3317                                                                 "preroll-handoff",
3318                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3319                                                                 (gpointer)player);
3320         }
3321
3322         if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3323                 return MM_ERROR_PLAYER_INTERNAL;
3324
3325         if (videobin[MMPLAYER_V_SINK].gst) {
3326                 GstPad *sink_pad = NULL;
3327                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3328                 if (sink_pad) {
3329                         __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3330                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3331                         gst_object_unref(GST_OBJECT(sink_pad));
3332                 } else {
3333                         LOGE("failed to get sink pad from videosink");
3334                 }
3335         }
3336
3337         return MM_ERROR_NONE;
3338 }
3339
3340 /**
3341  * VIDEO BIN
3342  * - video overlay surface(arm/x86) : tizenwlsink
3343  */
3344 static int
3345 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3346 {
3347         GstPad *pad = NULL;
3348         GList *element_bucket = NULL;
3349         MMPlayerGstElement *first_element = NULL;
3350         MMPlayerGstElement *videobin = NULL;
3351         gchar *videosink_factory_name = NULL;
3352
3353         MMPLAYER_FENTER();
3354         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3355
3356         /* alloc handles */
3357         videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3358         if (!videobin)
3359                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3360
3361         player->pipeline->videobin = videobin;
3362
3363         /* create bin */
3364         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3365         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3366         if (!videobin[MMPLAYER_V_BIN].gst) {
3367                 LOGE("failed to create videobin");
3368                 goto ERROR;
3369         }
3370
3371         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3372                 goto ERROR;
3373
3374         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3375         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3376
3377         /* additional setting for sink plug-in */
3378         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3379                 LOGE("failed to set video property");
3380                 goto ERROR;
3381         }
3382
3383         /* store it as it's sink element */
3384         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3385
3386         /* adding created elements to bin */
3387         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3388                 LOGE("failed to add elements");
3389                 goto ERROR;
3390         }
3391
3392         /* Linking elements in the bucket by added order */
3393         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3394                 LOGE("failed to link elements");
3395                 goto ERROR;
3396         }
3397
3398         /* get first element's sinkpad for creating ghostpad */
3399         first_element = (MMPlayerGstElement *)element_bucket->data;
3400         if (!first_element) {
3401                 LOGE("failed to get first element from bucket");
3402                 goto ERROR;
3403         }
3404
3405         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3406         if (!pad) {
3407                 LOGE("failed to get pad from first element");
3408                 goto ERROR;
3409         }
3410
3411         /* create ghostpad */
3412         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3413         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3414                 LOGE("failed to add ghostpad to videobin");
3415                 goto ERROR;
3416         }
3417         gst_object_unref(pad);
3418
3419         /* done. free allocated variables */
3420         g_list_free(element_bucket);
3421
3422         MMPLAYER_FLEAVE();
3423
3424         return MM_ERROR_NONE;
3425
3426 ERROR:
3427         LOGE("ERROR : releasing videobin");
3428         g_list_free(element_bucket);
3429
3430         if (pad)
3431                 gst_object_unref(GST_OBJECT(pad));
3432
3433         /* release videobin with it's childs */
3434         if (videobin[MMPLAYER_V_BIN].gst)
3435                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3436
3437         MMPLAYER_FREEIF(videobin);
3438         player->pipeline->videobin = NULL;
3439
3440         return MM_ERROR_PLAYER_INTERNAL;
3441 }
3442
3443 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3444 {
3445         GList *element_bucket = NULL;
3446         MMPlayerGstElement *textbin = player->pipeline->textbin;
3447
3448         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3449         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3450         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3451                                                         "signal-handoffs", FALSE,
3452                                                         NULL);
3453
3454         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3455         __mmplayer_add_signal_connection(player,
3456                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3457                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3458                                                         "handoff",
3459                                                         G_CALLBACK(__mmplayer_update_subtitle),
3460                                                         (gpointer)player);
3461
3462         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3463                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3464
3465         if (!player->play_subtitle) {
3466                 LOGD("add textbin sink as sink element of whole pipeline.\n");
3467                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3468         }
3469
3470         /* adding created elements to bin */
3471         LOGD("adding created elements to bin\n");
3472         if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3473                 LOGE("failed to add elements\n");
3474                 goto ERROR;
3475         }
3476
3477         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3478         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3479         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3480
3481         /* linking elements in the bucket by added order. */
3482         LOGD("Linking elements in the bucket by added order.\n");
3483         if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3484                 LOGE("failed to link elements\n");
3485                 goto ERROR;
3486         }
3487
3488         /* done. free allocated variables */
3489         g_list_free(element_bucket);
3490
3491         if (textbin[MMPLAYER_T_QUEUE].gst) {
3492                 GstPad *pad = NULL;
3493                 GstPad *ghostpad = NULL;
3494
3495                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3496                 if (!pad) {
3497                         LOGE("failed to get sink pad of text queue");
3498                         goto ERROR;
3499                 }
3500
3501                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3502                 gst_object_unref(pad);
3503
3504                 if (!ghostpad) {
3505                         LOGE("failed to create ghostpad of textbin\n");
3506                         goto ERROR;
3507                 }
3508
3509                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3510                         LOGE("failed to add ghostpad to textbin\n");
3511                         gst_object_unref(ghostpad);
3512                         goto ERROR;
3513                 }
3514         }
3515
3516         return MM_ERROR_NONE;
3517
3518 ERROR:
3519         g_list_free(element_bucket);
3520
3521         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3522                 LOGE("remove textbin sink from sink list");
3523                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3524         }
3525
3526         /* release element at __mmplayer_gst_create_text_sink_bin */
3527         return MM_ERROR_PLAYER_INTERNAL;
3528 }
3529
3530 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3531 {
3532         MMPlayerGstElement *textbin = NULL;
3533         GList *element_bucket = NULL;
3534         int surface_type = 0;
3535         gint i = 0;
3536
3537         MMPLAYER_FENTER();
3538
3539         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3540
3541         /* alloc handles */
3542         textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3543         if (!textbin) {
3544                 LOGE("failed to allocate memory for textbin\n");
3545                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3546         }
3547
3548         /* create bin */
3549         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3550         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3551         if (!textbin[MMPLAYER_T_BIN].gst) {
3552                 LOGE("failed to create textbin\n");
3553                 goto ERROR;
3554         }
3555
3556         /* take it */
3557         player->pipeline->textbin = textbin;
3558
3559         /* fakesink */
3560         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3561         LOGD("surface type for subtitle : %d", surface_type);
3562         switch (surface_type) {
3563         case MM_DISPLAY_SURFACE_OVERLAY:
3564         case MM_DISPLAY_SURFACE_NULL:
3565         case MM_DISPLAY_SURFACE_REMOTE:
3566                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3567                         LOGE("failed to make plain text elements\n");
3568                         goto ERROR;
3569                 }
3570                 break;
3571         default:
3572                 goto ERROR;
3573                 break;
3574         }
3575
3576         MMPLAYER_FLEAVE();
3577
3578         return MM_ERROR_NONE;
3579
3580 ERROR:
3581
3582         LOGD("ERROR : releasing textbin\n");
3583
3584         g_list_free(element_bucket);
3585
3586         /* release signal */
3587         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3588
3589         /* release element which are not added to bin */
3590         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3591                 /* NOTE : skip bin */
3592                 if (textbin[i].gst) {
3593                         GstObject* parent = NULL;
3594                         parent = gst_element_get_parent(textbin[i].gst);
3595
3596                         if (!parent) {
3597                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3598                                 textbin[i].gst = NULL;
3599                         } else {
3600                                 gst_object_unref(GST_OBJECT(parent));
3601                         }
3602                 }
3603         }
3604
3605         /* release textbin with it's childs */
3606         if (textbin[MMPLAYER_T_BIN].gst)
3607                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3608
3609         MMPLAYER_FREEIF(player->pipeline->textbin);
3610         player->pipeline->textbin = NULL;
3611
3612         MMPLAYER_FLEAVE();
3613         return MM_ERROR_PLAYER_INTERNAL;
3614 }
3615
3616
3617 static int
3618 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3619 {
3620         MMPlayerGstElement* mainbin = NULL;
3621         MMPlayerGstElement* textbin = NULL;
3622         MMHandleType attrs = 0;
3623         GstElement *subsrc = NULL;
3624         GstElement *subparse = NULL;
3625         gchar *subtitle_uri = NULL;
3626         const gchar *charset = NULL;
3627         GstPad *pad = NULL;
3628
3629         MMPLAYER_FENTER();
3630
3631         /* get mainbin */
3632         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3633                                                                 player->pipeline &&
3634                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3635
3636         mainbin = player->pipeline->mainbin;
3637
3638         attrs = MMPLAYER_GET_ATTRS(player);
3639         if (!attrs) {
3640                 LOGE("cannot get content attribute\n");
3641                 return MM_ERROR_PLAYER_INTERNAL;
3642         }
3643
3644         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3645         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3646                 LOGE("subtitle uri is not proper filepath.\n");
3647                 return MM_ERROR_PLAYER_INVALID_URI;
3648         }
3649
3650         if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3651                 LOGE("failed to get storage info of subtitle path");
3652                 return MM_ERROR_PLAYER_INVALID_URI;
3653         }
3654
3655         SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3656
3657         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3658         player->subtitle_language_list = NULL;
3659         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3660
3661         /* create the subtitle source */
3662         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3663         if (!subsrc) {
3664                 LOGE("failed to create filesrc element\n");
3665                 goto ERROR;
3666         }
3667         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3668
3669         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3670         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3671
3672         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3673                 LOGW("failed to add queue\n");
3674                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3675                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3676                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3677                 goto ERROR;
3678         }
3679
3680         /* subparse */
3681         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3682         if (!subparse) {
3683                 LOGE("failed to create subparse element\n");
3684                 goto ERROR;
3685         }
3686
3687         charset = util_get_charset(subtitle_uri);
3688         if (charset) {
3689                 LOGD("detected charset is %s\n", charset);
3690                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3691         }
3692
3693         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3694         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3695
3696         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3697                 LOGW("failed to add subparse\n");
3698                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3699                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3700                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3701                 goto ERROR;
3702         }
3703
3704         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3705                 LOGW("failed to link subsrc and subparse\n");
3706                 goto ERROR;
3707         }
3708
3709         player->play_subtitle = TRUE;
3710         player->adjust_subtitle_pos = 0;
3711
3712         LOGD("play subtitle using subtitle file\n");
3713
3714         if (player->pipeline->textbin == NULL) {
3715                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3716                         LOGE("failed to create text sink bin. continuing without text\n");
3717                         goto ERROR;
3718                 }
3719
3720                 textbin = player->pipeline->textbin;
3721
3722                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3723                         LOGW("failed to add textbin\n");
3724
3725                         /* release signal */
3726                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3727
3728                         /* release textbin with it's childs */
3729                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3730                         MMPLAYER_FREEIF(player->pipeline->textbin);
3731                         player->pipeline->textbin = textbin = NULL;
3732                         goto ERROR;
3733                 }
3734
3735                 LOGD("link text input selector and textbin ghost pad");
3736
3737                 player->textsink_linked = 1;
3738                 player->external_text_idx = 0;
3739                 LOGI("player->textsink_linked set to 1\n");
3740         } else {
3741                 textbin = player->pipeline->textbin;
3742                 LOGD("text bin has been created. reuse it.");
3743                 player->external_text_idx = 1;
3744         }
3745
3746         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3747                 LOGW("failed to link subparse and textbin\n");
3748                 goto ERROR;
3749         }
3750
3751         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3752         if (!pad) {
3753                 LOGE("failed to get sink pad from textsink to probe data");
3754                 goto ERROR;
3755         }
3756
3757         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3758                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3759
3760         gst_object_unref(pad);
3761         pad = NULL;
3762
3763         /* create dot. for debugging */
3764         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3765         MMPLAYER_FLEAVE();
3766
3767         return MM_ERROR_NONE;
3768
3769 ERROR:
3770         /* release text pipeline resource */
3771         player->textsink_linked = 0;
3772
3773         /* release signal */
3774         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3775
3776         if (player->pipeline->textbin) {
3777                 LOGE("remove textbin");
3778
3779                 /* release textbin with it's childs */
3780                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3781                 MMPLAYER_FREEIF(player->pipeline->textbin);
3782                 player->pipeline->textbin = NULL;
3783
3784         }
3785
3786         /* release subtitle elem */
3787         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3788         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3789
3790         return MM_ERROR_PLAYER_INTERNAL;
3791 }
3792
3793 gboolean
3794 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3795 {
3796         mm_player_t* player = (mm_player_t*) data;
3797         MMMessageParamType msg = {0, };
3798         GstClockTime duration = 0;
3799         gpointer text = NULL;
3800         guint text_size = 0;
3801         gboolean ret = TRUE;
3802         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3803
3804         MMPLAYER_FENTER();
3805
3806         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3807         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3808
3809         if (player->is_subtitle_force_drop) {
3810                 LOGW("subtitle is dropped forcedly.");
3811                 return ret;
3812         }
3813
3814         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3815         text = mapinfo.data;
3816         text_size = mapinfo.size;
3817         duration = GST_BUFFER_DURATION(buffer);
3818
3819         if (player->set_mode.subtitle_off) {
3820                 LOGD("subtitle is OFF.\n");
3821                 return TRUE;
3822         }
3823
3824         if (!text || (text_size == 0)) {
3825                 LOGD("There is no subtitle to be displayed.\n");
3826                 return TRUE;
3827         }
3828
3829         msg.data = (void *) text;
3830         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3831
3832         LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3833
3834         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3835         gst_buffer_unmap(buffer, &mapinfo);
3836
3837         MMPLAYER_FLEAVE();
3838
3839         return ret;
3840 }
3841
3842 static GstPadProbeReturn
3843 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3844 {
3845         mm_player_t *player = (mm_player_t *) u_data;
3846         GstClockTime cur_timestamp = 0;
3847         gint64 adjusted_timestamp = 0;
3848         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3849
3850         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3851
3852         if (player->set_mode.subtitle_off) {
3853                 LOGD("subtitle is OFF.\n");
3854                 return TRUE;
3855         }
3856
3857         if (player->adjust_subtitle_pos == 0) {
3858                 LOGD("nothing to do");
3859                 return TRUE;
3860         }
3861
3862         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3863         adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3864
3865         if (adjusted_timestamp < 0) {
3866                 LOGD("adjusted_timestamp under zero");
3867                 MMPLAYER_FLEAVE();
3868                 return FALSE;
3869         }
3870
3871         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3872         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3873                                 GST_TIME_ARGS(cur_timestamp),
3874                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3875
3876         return GST_PAD_PROBE_OK;
3877 }
3878 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3879 {
3880         MMPLAYER_FENTER();
3881
3882         /* check player and subtitlebin are created */
3883         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3885
3886         if (position == 0) {
3887                 LOGD("nothing to do\n");
3888                 MMPLAYER_FLEAVE();
3889                 return MM_ERROR_NONE;
3890         }
3891
3892         switch (format) {
3893         case MM_PLAYER_POS_FORMAT_TIME:
3894                 {
3895                         /* check current postion */
3896                         player->adjust_subtitle_pos = position;
3897
3898                         LOGD("save adjust_subtitle_pos in player") ;
3899                 }
3900                 break;
3901
3902         default:
3903                 {
3904                         LOGW("invalid format.\n");
3905                         MMPLAYER_FLEAVE();
3906                         return MM_ERROR_INVALID_ARGUMENT;
3907                 }
3908         }
3909
3910         MMPLAYER_FLEAVE();
3911
3912         return MM_ERROR_NONE;
3913 }
3914
3915 /**
3916  * This function is to create  audio or video pipeline for playing.
3917  *
3918  * @param       player          [in]    handle of player
3919  *
3920  * @return      This function returns zero on success.
3921  * @remark
3922  * @see
3923  */
3924 static int
3925 __mmplayer_gst_create_pipeline(mm_player_t* player)
3926 {
3927         int ret = MM_ERROR_NONE;
3928         MMPlayerGstElement *mainbin = NULL;
3929         MMHandleType attrs = 0;
3930         gint mode = MM_PLAYER_PD_MODE_NONE;
3931
3932         MMPLAYER_FENTER();
3933         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3934
3935         /* get profile attribute */
3936         attrs = MMPLAYER_GET_ATTRS(player);
3937         if (!attrs) {
3938                 LOGE("failed to get content attribute");
3939                 goto INIT_ERROR;
3940         }
3941
3942         /* create pipeline handles */
3943         if (player->pipeline) {
3944                 LOGE("pipeline should be released before create new one");
3945                 goto INIT_ERROR;
3946         }
3947
3948         player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3949         if (player->pipeline == NULL)
3950                 goto INIT_ERROR;
3951
3952         /* create mainbin */
3953         mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3954         if (mainbin == NULL)
3955                 goto INIT_ERROR;
3956
3957         /* create pipeline */
3958         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3959         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3960         if (!mainbin[MMPLAYER_M_PIPE].gst) {
3961                 LOGE("failed to create pipeline");
3962                 g_free(mainbin);
3963                 goto INIT_ERROR;
3964         }
3965
3966         player->pipeline->mainbin = mainbin;
3967
3968         /* check pd mode */
3969         mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
3970         player->pd_mode = mode;
3971
3972         /* create the source and decoder elements */
3973         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3974                 ret = __mmplayer_gst_build_es_pipeline(player);
3975         } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
3976                 ret = __mmplayer_gst_build_pd_pipeline(player);
3977         } else {
3978                 ret = __mmplayer_gst_build_pipeline(player);
3979         }
3980
3981         if (ret != MM_ERROR_NONE) {
3982                 LOGE("failed to create some elements");
3983                 goto INIT_ERROR;
3984         }
3985
3986         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3987         if (__mmplayer_check_subtitle(player)) {
3988                 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
3989                         LOGE("failed to create text pipeline");
3990         }
3991
3992         /* add bus watch */
3993         ret = __mmplayer_gst_add_bus_watch(player);
3994         if (ret != MM_ERROR_NONE) {
3995                 LOGE("failed to add bus watch");
3996                 goto INIT_ERROR;
3997         }
3998
3999         MMPLAYER_FLEAVE();
4000         return MM_ERROR_NONE;
4001
4002 INIT_ERROR:
4003         __mmplayer_gst_destroy_pipeline(player);
4004         return MM_ERROR_PLAYER_INTERNAL;
4005 }
4006
4007 static void
4008 __mmplayer_reset_gapless_state(mm_player_t* player)
4009 {
4010         MMPLAYER_FENTER();
4011         MMPLAYER_RETURN_IF_FAIL(player
4012                 && player->pipeline
4013                 && player->pipeline->audiobin
4014                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4015
4016         memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4017
4018         MMPLAYER_FLEAVE();
4019         return;
4020 }
4021
4022 static int
4023 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4024 {
4025         gint timeout = 0;
4026         int ret = MM_ERROR_NONE;
4027
4028         MMPLAYER_FENTER();
4029
4030         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4031
4032         /* cleanup stuffs */
4033         MMPLAYER_FREEIF(player->type);
4034         player->no_more_pad = FALSE;
4035         player->num_dynamic_pad = 0;
4036         player->demux_pad_index = 0;
4037
4038         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4039         player->subtitle_language_list = NULL;
4040         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4041
4042         __mmplayer_reset_gapless_state(player);
4043
4044         if (player->streamer) {
4045                 __mm_player_streaming_deinitialize(player->streamer);
4046                 __mm_player_streaming_destroy(player->streamer);
4047                 player->streamer = NULL;
4048         }
4049
4050         /* cleanup unlinked mime type */
4051         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4052         MMPLAYER_FREEIF(player->unlinked_video_mime);
4053         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4054
4055         /* cleanup running stuffs */
4056         __mmplayer_cancel_eos_timer(player);
4057
4058         /* cleanup gst stuffs */
4059         if (player->pipeline) {
4060                 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4061                 GstTagList* tag_list = player->pipeline->tag_list;
4062
4063                 /* first we need to disconnect all signal hander */
4064                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4065
4066                 if (mainbin) {
4067                         MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4068                         MMPlayerGstElement* videobin = player->pipeline->videobin;
4069                         MMPlayerGstElement* textbin = player->pipeline->textbin;
4070                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4071                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4072                         gst_object_unref(bus);
4073
4074                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4075                         ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4076                         if (ret != MM_ERROR_NONE) {
4077                                 LOGE("fail to change state to NULL\n");
4078                                 return MM_ERROR_PLAYER_INTERNAL;
4079                         }
4080
4081                         LOGW("succeeded in changing state to NULL\n");
4082
4083                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4084
4085                         /* free fakesink */
4086                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4087                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4088
4089                         /* free avsysaudiosink
4090                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4091                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4092                         */
4093                         MMPLAYER_FREEIF(audiobin);
4094                         MMPLAYER_FREEIF(videobin);
4095                         MMPLAYER_FREEIF(textbin);
4096                         MMPLAYER_FREEIF(mainbin);
4097                 }
4098
4099                 if (tag_list)
4100                         gst_tag_list_free(tag_list);
4101
4102                 MMPLAYER_FREEIF(player->pipeline);
4103         }
4104         MMPLAYER_FREEIF(player->album_art);
4105
4106         if (player->v_stream_caps) {
4107                 gst_caps_unref(player->v_stream_caps);
4108                 player->v_stream_caps = NULL;
4109         }
4110         if (player->a_stream_caps) {
4111                 gst_caps_unref(player->a_stream_caps);
4112                 player->a_stream_caps = NULL;
4113         }
4114
4115         if (player->s_stream_caps) {
4116                 gst_caps_unref(player->s_stream_caps);
4117                 player->s_stream_caps = NULL;
4118         }
4119         __mmplayer_track_destroy(player);
4120
4121         if (player->sink_elements)
4122                 g_list_free(player->sink_elements);
4123         player->sink_elements = NULL;
4124
4125         if (player->bufmgr) {
4126                 tbm_bufmgr_deinit(player->bufmgr);
4127                 player->bufmgr = NULL;
4128         }
4129
4130         LOGW("finished destroy pipeline\n");
4131
4132         MMPLAYER_FLEAVE();
4133
4134         return ret;
4135 }
4136
4137 static int __mmplayer_gst_realize(mm_player_t* player)
4138 {
4139         gint timeout = 0;
4140         int ret = MM_ERROR_NONE;
4141
4142         MMPLAYER_FENTER();
4143
4144         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4145
4146         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4147
4148         ret = __mmplayer_gst_create_pipeline(player);
4149         if (ret) {
4150                 LOGE("failed to create pipeline\n");
4151                 return ret;
4152         }
4153
4154         /* set pipeline state to READY */
4155         /* NOTE : state change to READY must be performed sync. */
4156         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4157         ret = __mmplayer_gst_set_state(player,
4158                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4159
4160         if (ret != MM_ERROR_NONE) {
4161                 /* return error if failed to set state */
4162                 LOGE("failed to set READY state");
4163                 return ret;
4164         }
4165
4166         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4167
4168         /* create dot before error-return. for debugging */
4169         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4170
4171         MMPLAYER_FLEAVE();
4172
4173         return ret;
4174 }
4175
4176 static int __mmplayer_gst_unrealize(mm_player_t* player)
4177 {
4178         int ret = MM_ERROR_NONE;
4179
4180         MMPLAYER_FENTER();
4181
4182         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4183
4184         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4185         MMPLAYER_PRINT_STATE(player);
4186
4187         /* release miscellaneous information */
4188         __mmplayer_release_misc(player);
4189
4190         /* destroy pipeline */
4191         ret = __mmplayer_gst_destroy_pipeline(player);
4192         if (ret != MM_ERROR_NONE) {
4193                 LOGE("failed to destory pipeline\n");
4194                 return ret;
4195         }
4196
4197         /* release miscellaneous information.
4198            these info needs to be released after pipeline is destroyed. */
4199         __mmplayer_release_misc_post(player);
4200
4201         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4202
4203         MMPLAYER_FLEAVE();
4204
4205         return ret;
4206 }
4207
4208 static int
4209 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4210 {
4211         MMPLAYER_FENTER();
4212
4213         if (!player) {
4214                 LOGW("set_message_callback is called with invalid player handle\n");
4215                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4216         }
4217
4218         player->msg_cb = callback;
4219         player->msg_cb_param = user_param;
4220
4221         LOGD("msg_cb : %p     msg_cb_param : %p\n", callback, user_param);
4222
4223         MMPLAYER_FLEAVE();
4224
4225         return MM_ERROR_NONE;
4226 }
4227
4228 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4229 {
4230         int ret = MM_ERROR_NONE;
4231         char *path = NULL;
4232
4233         MMPLAYER_FENTER();
4234
4235         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4236         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4237         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4238
4239         memset(data, 0, sizeof(MMPlayerParseProfile));
4240
4241         if (strstr(uri, "es_buff://")) {
4242                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4243         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4244                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4245         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4246                 gchar *tmp = NULL;
4247                 tmp = g_ascii_strdown(uri, strlen(uri));
4248                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4249                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4250                 else
4251                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4252                 g_free(tmp);
4253         } else if (strstr(uri, "mms://")) {
4254                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4255         } else if ((path = strstr(uri, "mem://"))) {
4256                 ret = __mmplayer_set_mem_uri(data, path, param);
4257         } else {
4258                 ret = __mmplayer_set_file_uri(data, uri);
4259         }
4260
4261         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4262                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4263         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4264                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4265
4266         /* dump parse result */
4267         SECURE_LOGW("incoming uri : %s\n", uri);
4268         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4269                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4270
4271         MMPLAYER_FLEAVE();
4272
4273         return ret;
4274 }
4275
4276 static gboolean
4277 __mmplayer_can_do_interrupt(mm_player_t *player)
4278 {
4279         if (!player || !player->pipeline || !player->attrs) {
4280                 LOGW("not initialized");
4281                 goto FAILED;
4282         }
4283
4284         if (player->audio_stream_render_cb) {
4285                 LOGW("not support in pcm extraction mode");
4286                 goto FAILED;
4287         }
4288
4289         /* check if seeking */
4290         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4291                 MMMessageParamType msg_param;
4292                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4293                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4294                 player->seek_state = MMPLAYER_SEEK_NONE;
4295                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4296                 goto FAILED;
4297         }
4298
4299         /* check other thread */
4300         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4301                 LOGW("locked already, cmd state : %d", player->cmd);
4302
4303                 /* check application command */
4304                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4305                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4306
4307                         /* lock will be released at mrp_resource_release_cb() */
4308                         MMPLAYER_CMD_LOCK(player);
4309                         goto INTERRUPT;
4310                 }
4311                 LOGW("nothing to do");
4312                 goto FAILED;
4313         } else {
4314                 LOGW("can interrupt immediately");
4315                 goto INTERRUPT;
4316         }
4317
4318 FAILED:    /* with CMD UNLOCKED */
4319         return FALSE;
4320
4321 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4322         return TRUE;
4323 }
4324
4325 static int
4326 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4327                 void *user_data)
4328 {
4329         mm_player_t *player = NULL;
4330
4331         MMPLAYER_FENTER();
4332
4333         if (user_data == NULL) {
4334                 LOGE("- user_data is null\n");
4335                 return FALSE;
4336         }
4337         player = (mm_player_t *)user_data;
4338
4339         /* do something to release resource here.
4340          * player stop and interrupt forwarding */
4341         if (!__mmplayer_can_do_interrupt(player)) {
4342                 LOGW("no need to interrupt, so leave");
4343         } else {
4344                 MMMessageParamType msg = {0, };
4345                 gint64 pos = 0;
4346
4347                 player->interrupted_by_resource = TRUE;
4348
4349                 /* get last play position */
4350                 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4351                         LOGW("failed to get play position.");
4352                 } else {
4353                         msg.union_type = MM_MSG_UNION_TIME;
4354                         msg.time.elapsed = pos;
4355                         MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4356                 }
4357                 LOGD("video resource conflict so, resource will be freed by unrealizing");
4358                 if (_mmplayer_unrealize((MMHandleType)player))
4359                         LOGW("failed to unrealize");
4360
4361                 /* lock is called in __mmplayer_can_do_interrupt() */
4362                 MMPLAYER_CMD_UNLOCK(player);
4363         }
4364
4365         if (res == player->video_overlay_resource)
4366                 player->video_overlay_resource = FALSE;
4367         else
4368                 player->video_decoder_resource = FALSE;
4369
4370         MMPLAYER_FLEAVE();
4371
4372         return FALSE;
4373 }
4374
4375 static void
4376 __mmplayer_initialize_video_roi(mm_player_t *player)
4377 {
4378         player->video_roi.scale_x = 0.0;
4379         player->video_roi.scale_y = 0.0;
4380         player->video_roi.scale_width = 1.0;
4381         player->video_roi.scale_height = 1.0;
4382 }
4383
4384 int
4385 _mmplayer_create_player(MMHandleType handle)
4386 {
4387         int ret = MM_ERROR_PLAYER_INTERNAL;
4388         bool enabled = false;
4389
4390         mm_player_t* player = MM_PLAYER_CAST(handle);
4391
4392         MMPLAYER_FENTER();
4393
4394         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4395
4396         /* initialize player state */
4397         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4398         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4399         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4400         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4401
4402         /* check current state */
4403         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4404
4405         /* construct attributes */
4406         player->attrs = _mmplayer_construct_attribute(handle);
4407
4408         if (!player->attrs) {
4409                 LOGE("Failed to construct attributes\n");
4410                 return ret;
4411         }
4412
4413         /* initialize gstreamer with configured parameter */
4414         if (!__mmplayer_init_gstreamer(player)) {
4415                 LOGE("Initializing gstreamer failed\n");
4416                 _mmplayer_deconstruct_attribute(handle);
4417                 return ret;
4418         }
4419
4420         /* create lock. note that g_tread_init() has already called in gst_init() */
4421         g_mutex_init(&player->fsink_lock);
4422
4423         /* create update tag lock */
4424         g_mutex_init(&player->update_tag_lock);
4425
4426         /* create gapless play mutex */
4427         g_mutex_init(&player->gapless_play_thread_mutex);
4428
4429         /* create gapless play cond */
4430         g_cond_init(&player->gapless_play_thread_cond);
4431
4432         /* create gapless play thread */
4433         player->gapless_play_thread =
4434                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4435         if (!player->gapless_play_thread) {
4436                 LOGE("failed to create gapless play thread");
4437                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4438                 g_mutex_clear(&player->gapless_play_thread_mutex);
4439                 g_cond_clear(&player->gapless_play_thread_cond);
4440                 goto ERROR;
4441         }
4442
4443         player->bus_msg_q = g_queue_new();
4444         if (!player->bus_msg_q) {
4445                 LOGE("failed to create queue for bus_msg");
4446                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4447                 goto ERROR;
4448         }
4449
4450         ret = _mmplayer_initialize_video_capture(player);
4451         if (ret != MM_ERROR_NONE) {
4452                 LOGE("failed to initialize video capture\n");
4453                 goto ERROR;
4454         }
4455
4456         /* initialize resource manager */
4457         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4458                         MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4459                         &player->resource_manager)) {
4460                 LOGE("failed to initialize resource manager\n");
4461                 ret = MM_ERROR_PLAYER_INTERNAL;
4462                 goto ERROR;
4463         }
4464
4465         if (MMPLAYER_IS_HTTP_PD(player)) {
4466                 player->pd_downloader = NULL;
4467                 player->pd_file_save_path = NULL;
4468         }
4469
4470         /* create video bo lock and cond */
4471         g_mutex_init(&player->video_bo_mutex);
4472         g_cond_init(&player->video_bo_cond);
4473
4474         /* create media stream callback mutex */
4475         g_mutex_init(&player->media_stream_cb_lock);
4476
4477         /* create subtitle info lock and cond */
4478         g_mutex_init(&player->subtitle_info_mutex);
4479         g_cond_init(&player->subtitle_info_cond);
4480
4481         player->streaming_type = STREAMING_SERVICE_NONE;
4482
4483         /* give default value of audio effect setting */
4484         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4485         player->sound.rg_enable = false;
4486         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4487
4488         player->play_subtitle = FALSE;
4489         player->has_closed_caption = FALSE;
4490         player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4491         player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4492         player->pending_resume = FALSE;
4493         if (player->ini.dump_element_keyword[0][0] == '\0')
4494                 player->ini.set_dump_element_flag = FALSE;
4495         else
4496                 player->ini.set_dump_element_flag = TRUE;
4497
4498         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4499         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4500         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4501
4502         /* Set video360 settings to their defaults for just-created player.
4503          * */
4504
4505         player->is_360_feature_enabled = FALSE;
4506         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4507                 LOGI("spherical feature info: %d", enabled);
4508                 if (enabled)
4509                         player->is_360_feature_enabled = TRUE;
4510         } else {
4511                 LOGE("failed to get spherical feature info");
4512         }
4513
4514         player->is_content_spherical = FALSE;
4515         player->is_video360_enabled = TRUE;
4516         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4517         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4518         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4519         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4520         player->video360_zoom = 1.0f;
4521         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4522         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4523
4524         __mmplayer_initialize_video_roi(player);
4525
4526         /* set player state to null */
4527         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4528         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4529
4530         return MM_ERROR_NONE;
4531
4532 ERROR:
4533         /* free lock */
4534         g_mutex_clear(&player->fsink_lock);
4535
4536         /* free update tag lock */
4537         g_mutex_clear(&player->update_tag_lock);
4538
4539         g_queue_free(player->bus_msg_q);
4540
4541         /* free gapless play thread */
4542         if (player->gapless_play_thread) {
4543                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4544                 player->gapless_play_thread_exit = TRUE;
4545                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4546                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4547
4548                 g_thread_join(player->gapless_play_thread);
4549                 player->gapless_play_thread = NULL;
4550
4551                 g_mutex_clear(&player->gapless_play_thread_mutex);
4552                 g_cond_clear(&player->gapless_play_thread_cond);
4553         }
4554
4555         /* release attributes */
4556         _mmplayer_deconstruct_attribute(handle);
4557
4558         MMPLAYER_FLEAVE();
4559
4560         return ret;
4561 }
4562
4563 static gboolean
4564 __mmplayer_init_gstreamer(mm_player_t* player)
4565 {
4566         static gboolean initialized = FALSE;
4567         static const int max_argc = 50;
4568         gint* argc = NULL;
4569         gchar** argv = NULL;
4570         gchar** argv2 = NULL;
4571         GError *err = NULL;
4572         int i = 0;
4573         int arg_count = 0;
4574
4575         if (initialized) {
4576                 LOGD("gstreamer already initialized.\n");
4577                 return TRUE;
4578         }
4579
4580         /* alloc */
4581         argc = malloc(sizeof(int));
4582         argv = malloc(sizeof(gchar*) * max_argc);
4583         argv2 = malloc(sizeof(gchar*) * max_argc);
4584
4585         if (!argc || !argv || !argv2)
4586                 goto ERROR;
4587
4588         memset(argv, 0, sizeof(gchar*) * max_argc);
4589         memset(argv2, 0, sizeof(gchar*) * max_argc);
4590
4591         /* add initial */
4592         *argc = 1;
4593         argv[0] = g_strdup("mmplayer");
4594
4595         /* add gst_param */
4596         for (i = 0; i < 5; i++) {
4597                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4598                 if (strlen(player->ini.gst_param[i]) > 0) {
4599                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4600                         (*argc)++;
4601                 }
4602         }
4603
4604         /* we would not do fork for scanning plugins */
4605         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4606         (*argc)++;
4607
4608         /* check disable registry scan */
4609         if (player->ini.skip_rescan) {
4610                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4611                 (*argc)++;
4612         }
4613
4614         /* check disable segtrap */
4615         if (player->ini.disable_segtrap) {
4616                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4617                 (*argc)++;
4618         }
4619
4620         LOGD("initializing gstreamer with following parameter\n");
4621         LOGD("argc : %d\n", *argc);
4622         arg_count = *argc;
4623
4624         for (i = 0; i < arg_count; i++) {
4625                 argv2[i] = argv[i];
4626                 LOGD("argv[%d] : %s\n", i, argv2[i]);
4627         }
4628
4629         /* initializing gstreamer */
4630         if (!gst_init_check(argc, &argv, &err)) {
4631                 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4632                 if (err)
4633                         g_error_free(err);
4634
4635                 goto ERROR;
4636         }
4637         /* release */
4638         for (i = 0; i < arg_count; i++) {
4639                 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4640                 MMPLAYER_FREEIF(argv2[i]);
4641         }
4642
4643         MMPLAYER_FREEIF(argv);
4644         MMPLAYER_FREEIF(argv2);
4645         MMPLAYER_FREEIF(argc);
4646
4647         /* done */
4648         initialized = TRUE;
4649
4650         return TRUE;
4651
4652 ERROR:
4653
4654         /* release */
4655         for (i = 0; i < arg_count; i++) {
4656                 LOGD("free[%d] : %s\n", i, argv2[i]);
4657                 MMPLAYER_FREEIF(argv2[i]);
4658         }
4659
4660         MMPLAYER_FREEIF(argv);
4661         MMPLAYER_FREEIF(argv2);
4662         MMPLAYER_FREEIF(argc);
4663
4664         return FALSE;
4665 }
4666
4667 int
4668 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4669 {
4670         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4671
4672         if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4673                 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4674                 MMPLAYER_FREEIF(player->pd_file_save_path);
4675         }
4676
4677         return MM_ERROR_NONE;
4678 }
4679
4680 static void
4681 __mmplayer_check_async_state_transition(mm_player_t* player)
4682 {
4683         GstState element_state = GST_STATE_VOID_PENDING;
4684         GstState element_pending_state = GST_STATE_VOID_PENDING;
4685         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4686         GstElement * element = NULL;
4687         gboolean async = FALSE;
4688
4689         /* check player handle */
4690         MMPLAYER_RETURN_IF_FAIL(player &&
4691                                                 player->pipeline &&
4692                                                 player->pipeline->mainbin &&
4693                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4694
4695         if (player->attrs)
4696                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4697
4698         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4699                 LOGD("don't need to check the pipeline state");
4700                 return;
4701         }
4702
4703         MMPLAYER_PRINT_STATE(player);
4704
4705         /* wait for state transition */
4706         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4707         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4708
4709         if (ret == GST_STATE_CHANGE_FAILURE) {
4710                 LOGE(" [%s] state : %s   pending : %s \n",
4711                         GST_ELEMENT_NAME(element),
4712                         gst_element_state_get_name(element_state),
4713                         gst_element_state_get_name(element_pending_state));
4714
4715                 /* dump state of all element */
4716                 __mmplayer_dump_pipeline_state(player);
4717
4718                 return;
4719         }
4720
4721         LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4722         return;
4723 }
4724
4725 int
4726 _mmplayer_destroy(MMHandleType handle)
4727 {
4728         mm_player_t* player = MM_PLAYER_CAST(handle);
4729
4730         MMPLAYER_FENTER();
4731
4732         /* check player handle */
4733         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4734
4735         /* destroy can called at anytime */
4736         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4737
4738         /* check async state transition */
4739         __mmplayer_check_async_state_transition(player);
4740
4741         __mmplayer_destroy_streaming_ext(player);
4742
4743         /* release gapless play thread */
4744         if (player->gapless_play_thread) {
4745                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4746                 player->gapless_play_thread_exit = TRUE;
4747                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4748                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4749
4750                 LOGD("waitting for gapless play thread exit\n");
4751                 g_thread_join(player->gapless_play_thread);
4752                 g_mutex_clear(&player->gapless_play_thread_mutex);
4753                 g_cond_clear(&player->gapless_play_thread_cond);
4754                 LOGD("gapless play thread released\n");
4755         }
4756
4757         _mmplayer_release_video_capture(player);
4758
4759         /* de-initialize resource manager */
4760         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4761                         player->resource_manager))
4762                 LOGE("failed to deinitialize resource manager\n");
4763
4764         /* release pipeline */
4765         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4766                 LOGE("failed to destory pipeline\n");
4767                 return MM_ERROR_PLAYER_INTERNAL;
4768         }
4769
4770         g_queue_free(player->bus_msg_q);
4771
4772         /* release subtitle info lock and cond */
4773         g_mutex_clear(&player->subtitle_info_mutex);
4774         g_cond_clear(&player->subtitle_info_cond);
4775
4776         __mmplayer_release_dump_list(player->dump_list);
4777
4778         /* release miscellaneous information */
4779         __mmplayer_release_misc(player);
4780
4781         /* release miscellaneous information.
4782            these info needs to be released after pipeline is destroyed. */
4783         __mmplayer_release_misc_post(player);
4784
4785         /* release attributes */
4786         _mmplayer_deconstruct_attribute(handle);
4787
4788         /* release lock */
4789         g_mutex_clear(&player->fsink_lock);
4790
4791         /* release lock */
4792         g_mutex_clear(&player->update_tag_lock);
4793
4794         /* release video bo lock and cond */
4795         g_mutex_clear(&player->video_bo_mutex);
4796         g_cond_clear(&player->video_bo_cond);
4797
4798         /* release media stream callback lock */
4799         g_mutex_clear(&player->media_stream_cb_lock);
4800
4801         MMPLAYER_FLEAVE();
4802
4803         return MM_ERROR_NONE;
4804 }
4805
4806 int
4807 __mmplayer_realize_streaming_ext(mm_player_t* player)
4808 {
4809         int ret = MM_ERROR_NONE;
4810
4811         MMPLAYER_FENTER();
4812         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4813
4814         if (MMPLAYER_IS_HTTP_PD(player)) {
4815                 gboolean bret = FALSE;
4816
4817                 player->pd_downloader = _mmplayer_create_pd_downloader();
4818                 if (!player->pd_downloader) {
4819                         LOGE("Unable to create PD Downloader...");
4820                         ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4821                 }
4822
4823                 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4824
4825                 if (FALSE == bret) {
4826                         LOGE("Unable to create PD Downloader...");
4827                         ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
4828                 }
4829         }
4830
4831         MMPLAYER_FLEAVE();
4832         return ret;
4833 }
4834
4835 int
4836 _mmplayer_realize(MMHandleType hplayer)
4837 {
4838         mm_player_t* player = (mm_player_t*)hplayer;
4839         char *uri = NULL;
4840         void *param = NULL;
4841         MMHandleType attrs = 0;
4842         int ret = MM_ERROR_NONE;
4843
4844         MMPLAYER_FENTER();
4845
4846         /* check player handle */
4847         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4848
4849         /* check current state */
4850         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4851
4852         attrs = MMPLAYER_GET_ATTRS(player);
4853         if (!attrs) {
4854                 LOGE("fail to get attributes.\n");
4855                 return MM_ERROR_PLAYER_INTERNAL;
4856         }
4857         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4858         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
4859
4860         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4861                 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4862
4863                 if (ret != MM_ERROR_NONE) {
4864                         LOGE("failed to parse profile");
4865                         return ret;
4866                 }
4867         }
4868
4869         if (uri && (strstr(uri, "es_buff://"))) {
4870                 if (strstr(uri, "es_buff://push_mode"))
4871                         player->es_player_push_mode = TRUE;
4872                 else
4873                         player->es_player_push_mode = FALSE;
4874         }
4875
4876         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4877                 LOGW("mms protocol is not supported format.\n");
4878                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4879         }
4880
4881         if (MMPLAYER_IS_HTTP_PD(player))
4882                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
4883         else if (MMPLAYER_IS_STREAMING(player))
4884                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4885         else
4886                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4887
4888         player->smooth_streaming = FALSE;
4889         player->videodec_linked  = 0;
4890         player->audiodec_linked  = 0;
4891         player->textsink_linked = 0;
4892         player->is_external_subtitle_present = FALSE;
4893         player->is_external_subtitle_added_now = FALSE;
4894         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4895         player->video360_metadata.is_spherical = -1;
4896         player->is_openal_plugin_used = FALSE;
4897         player->demux_pad_index = 0;
4898         player->subtitle_language_list = NULL;
4899         player->is_subtitle_force_drop = FALSE;
4900         player->last_multiwin_status = FALSE;
4901
4902         __mmplayer_track_initialize(player);
4903         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4904
4905         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4906                 player->streamer = __mm_player_streaming_create();
4907                 __mm_player_streaming_initialize(player->streamer);
4908         }
4909
4910         /* realize pipeline */
4911         ret = __mmplayer_gst_realize(player);
4912         if (ret != MM_ERROR_NONE)
4913                 LOGE("fail to realize the player.\n");
4914         else
4915                 ret = __mmplayer_realize_streaming_ext(player);
4916
4917         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4918
4919         MMPLAYER_FLEAVE();
4920
4921         return ret;
4922 }
4923
4924 int
4925 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
4926 {
4927         MMPLAYER_FENTER();
4928         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4929
4930         /* destroy can called at anytime */
4931         if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
4932                 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
4933
4934         MMPLAYER_FLEAVE();
4935         return MM_ERROR_NONE;
4936 }
4937
4938 int
4939 _mmplayer_unrealize(MMHandleType hplayer)
4940 {
4941         mm_player_t* player = (mm_player_t*)hplayer;
4942         int ret = MM_ERROR_NONE;
4943
4944         MMPLAYER_FENTER();
4945
4946         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4947
4948         MMPLAYER_CMD_UNLOCK(player);
4949         /* destroy the gst bus msg thread which is created during realize.
4950            this funct have to be called before getting cmd lock. */
4951         __mmplayer_bus_msg_thread_destroy(player);
4952         MMPLAYER_CMD_LOCK(player);
4953
4954         /* check current state */
4955         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4956
4957         /* check async state transition */
4958         __mmplayer_check_async_state_transition(player);
4959
4960         __mmplayer_unrealize_streaming_ext(player);
4961
4962         /* unrealize pipeline */
4963         ret = __mmplayer_gst_unrealize(player);
4964
4965         /* set asm stop if success */
4966         if (MM_ERROR_NONE == ret) {
4967                 if (!player->interrupted_by_resource) {
4968                         if (player->video_decoder_resource != NULL) {
4969                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4970                                                 player->video_decoder_resource);
4971                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4972                                         LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4973                                 else
4974                                         player->video_decoder_resource = NULL;
4975                         }
4976
4977                         if (player->video_overlay_resource != NULL) {
4978                                 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4979                                                 player->video_overlay_resource);
4980                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4981                                         LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4982                                 else
4983                                         player->video_overlay_resource = NULL;
4984                         }
4985
4986                         ret = mm_resource_manager_commit(player->resource_manager);
4987                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4988                                 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4989                 }
4990         } else
4991                 LOGE("failed and don't change asm state to stop");
4992
4993         MMPLAYER_FLEAVE();
4994
4995         return ret;
4996 }
4997
4998 int
4999 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5000 {
5001         mm_player_t* player = (mm_player_t*)hplayer;
5002
5003         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5004
5005         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5006 }
5007
5008 int
5009 _mmplayer_get_state(MMHandleType hplayer, int* state)
5010 {
5011         mm_player_t *player = (mm_player_t*)hplayer;
5012
5013         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5014
5015         *state = MMPLAYER_CURRENT_STATE(player);
5016
5017         return MM_ERROR_NONE;
5018 }
5019
5020
5021 int
5022 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5023 {
5024         mm_player_t* player = (mm_player_t*) hplayer;
5025         GstElement* vol_element = NULL;
5026         int i = 0;
5027
5028         MMPLAYER_FENTER();
5029
5030         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5031
5032         LOGD("volume [L]=%f:[R]=%f\n",
5033                 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5034
5035         /* invalid factor range or not */
5036         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5037                 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5038                         LOGE("Invalid factor!(valid factor:0~1.0)\n");
5039                         return MM_ERROR_INVALID_ARGUMENT;
5040                 }
5041         }
5042
5043         /* not support to set other value into each channel */
5044         if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5045                 return MM_ERROR_INVALID_ARGUMENT;
5046
5047         /* Save volume to handle. Currently the first array element will be saved. */
5048         player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5049
5050         /* check pipeline handle */
5051         if (!player->pipeline || !player->pipeline->audiobin) {
5052                 LOGD("audiobin is not created yet\n");
5053                 LOGD("but, current stored volume will be set when it's created.\n");
5054
5055                 /* NOTE : stored volume will be used in create_audiobin
5056                  * returning MM_ERROR_NONE here makes application to able to
5057                  * set volume at anytime.
5058                  */
5059                 return MM_ERROR_NONE;
5060         }
5061
5062         /* setting volume to volume element */
5063         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5064
5065         if (vol_element) {
5066                 LOGD("volume is set [%f]\n", player->sound.volume);
5067                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5068         }
5069
5070         MMPLAYER_FLEAVE();
5071
5072         return MM_ERROR_NONE;
5073 }
5074
5075
5076 int
5077 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5078 {
5079         mm_player_t* player = (mm_player_t*) hplayer;
5080         int i = 0;
5081
5082         MMPLAYER_FENTER();
5083
5084         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5085         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5086
5087         /* returning stored volume */
5088         for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5089                 volume->level[i] = player->sound.volume;
5090
5091         MMPLAYER_FLEAVE();
5092
5093         return MM_ERROR_NONE;
5094 }
5095
5096 int
5097 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5098 {
5099         mm_player_t* player = (mm_player_t*) hplayer;
5100         GstElement* vol_element = NULL;
5101
5102         MMPLAYER_FENTER();
5103
5104         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5105
5106         /* mute value shoud 0 or 1 */
5107         if (mute != 0 && mute != 1) {
5108                 LOGE("bad mute value\n");
5109
5110                 /* FIXIT : definitly, we need _BAD_PARAM error code */
5111                 return MM_ERROR_INVALID_ARGUMENT;
5112         }
5113
5114         player->sound.mute = mute;
5115
5116         /* just hold mute value if pipeline is not ready */
5117         if (!player->pipeline || !player->pipeline->audiobin) {
5118                 LOGD("pipeline is not ready. holding mute value\n");
5119                 return MM_ERROR_NONE;
5120         }
5121
5122         vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5123
5124         /* NOTE : volume will only created when the bt is enabled */
5125         if (vol_element) {
5126                 LOGD("mute : %d\n", mute);
5127                 g_object_set(vol_element, "mute", mute, NULL);
5128         } else
5129                 LOGD("volume elemnet is not created. using volume in audiosink\n");
5130
5131         MMPLAYER_FLEAVE();
5132
5133         return MM_ERROR_NONE;
5134 }
5135
5136 int
5137 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5138 {
5139         mm_player_t* player = (mm_player_t*) hplayer;
5140
5141         MMPLAYER_FENTER();
5142
5143         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5144         MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5145
5146         /* just hold mute value if pipeline is not ready */
5147         if (!player->pipeline || !player->pipeline->audiobin) {
5148                 LOGD("pipeline is not ready. returning stored value\n");
5149                 *pmute = player->sound.mute;
5150                 return MM_ERROR_NONE;
5151         }
5152
5153         *pmute = player->sound.mute;
5154
5155         MMPLAYER_FLEAVE();
5156
5157         return MM_ERROR_NONE;
5158 }
5159
5160 int
5161 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5162 {
5163         mm_player_t* player = (mm_player_t*) hplayer;
5164
5165         MMPLAYER_FENTER();
5166
5167         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5168
5169         player->video_stream_changed_cb = callback;
5170         player->video_stream_changed_cb_user_param = user_param;
5171         LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5172
5173         MMPLAYER_FLEAVE();
5174
5175         return MM_ERROR_NONE;
5176 }
5177
5178 int
5179 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5180 {
5181         mm_player_t* player = (mm_player_t*) hplayer;
5182
5183         MMPLAYER_FENTER();
5184
5185         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186
5187         player->audio_stream_changed_cb = callback;
5188         player->audio_stream_changed_cb_user_param = user_param;
5189         LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5190
5191         MMPLAYER_FLEAVE();
5192
5193         return MM_ERROR_NONE;
5194 }
5195
5196 int
5197 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5198 {
5199         mm_player_t *player = (mm_player_t*) hplayer;
5200
5201         MMPLAYER_FENTER();
5202
5203         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5204
5205         player->audio_stream_render_cb = callback;
5206         player->audio_stream_cb_user_param = user_param;
5207         player->audio_stream_sink_sync = sync;
5208         LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5209
5210         MMPLAYER_FLEAVE();
5211
5212         return MM_ERROR_NONE;
5213 }
5214
5215 int
5216 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5217 {
5218         mm_player_t* player = (mm_player_t*) hplayer;
5219
5220         MMPLAYER_FENTER();
5221
5222         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5223
5224         if (callback && !player->bufmgr)
5225                 player->bufmgr = tbm_bufmgr_init(-1);
5226
5227         player->set_mode.media_packet_video_stream = (callback) ? true : false;
5228         player->video_stream_cb = callback;
5229         player->video_stream_cb_user_param = user_param;
5230
5231         LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5232
5233         MMPLAYER_FLEAVE();
5234
5235         return MM_ERROR_NONE;
5236 }
5237
5238 static int
5239 __mmplayer_start_streaming_ext(mm_player_t *player)
5240 {
5241         gint ret = MM_ERROR_NONE;
5242
5243         MMPLAYER_FENTER();
5244         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245
5246         if (MMPLAYER_IS_HTTP_PD(player)) {
5247                 if (!player->pd_downloader) {
5248                         ret = __mmplayer_realize_streaming_ext(player);
5249
5250                         if (ret != MM_ERROR_NONE) {
5251                                 LOGE("failed to realize streaming ext\n");
5252                                 return ret;
5253                         }
5254                 }
5255
5256                 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5257                         ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5258                         if (!ret) {
5259                                 LOGE("ERROR while starting PD...\n");
5260                                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5261                         }
5262                         ret = MM_ERROR_NONE;
5263                 }
5264         }
5265
5266         MMPLAYER_FLEAVE();
5267         return ret;
5268 }
5269
5270 int
5271 _mmplayer_start(MMHandleType hplayer)
5272 {
5273         mm_player_t* player = (mm_player_t*) hplayer;
5274         gint ret = MM_ERROR_NONE;
5275
5276         MMPLAYER_FENTER();
5277
5278         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5279
5280         /* check current state */
5281         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5282
5283         /* PD - start streaming */
5284         ret = __mmplayer_start_streaming_ext(player);
5285         if (ret != MM_ERROR_NONE) {
5286                 LOGE("failed to start streaming ext 0x%X", ret);
5287                 return ret;
5288         }
5289
5290         /* start pipeline */
5291         ret = __mmplayer_gst_start(player);
5292         if (ret != MM_ERROR_NONE)
5293                 LOGE("failed to start player.\n");
5294
5295         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5296                 LOGD("force playing start even during buffering");
5297                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5298         }
5299
5300         MMPLAYER_FLEAVE();
5301
5302         return ret;
5303 }
5304
5305 /* NOTE: post "not supported codec message" to application
5306  * when one codec is not found during AUTOPLUGGING in MSL.
5307  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5308  * And, if any codec is not found, don't send message here.
5309  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5310  */
5311 int
5312 __mmplayer_handle_missed_plugin(mm_player_t* player)
5313 {
5314         MMMessageParamType msg_param;
5315         memset(&msg_param, 0, sizeof(MMMessageParamType));
5316         gboolean post_msg_direct = FALSE;
5317
5318         MMPLAYER_FENTER();
5319
5320         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5321
5322         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5323                         player->not_supported_codec, player->can_support_codec);
5324
5325         if (player->not_found_demuxer) {
5326                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5327                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5328
5329                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5330                 MMPLAYER_FREEIF(msg_param.data);
5331
5332                 return MM_ERROR_NONE;
5333         }
5334
5335         if (player->not_supported_codec) {
5336                 if (player->can_support_codec) {
5337                         // There is one codec to play
5338                         post_msg_direct = TRUE;
5339                 } else {
5340                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5341                                 post_msg_direct = TRUE;
5342                 }
5343
5344                 if (post_msg_direct) {
5345                         MMMessageParamType msg_param;
5346                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5347
5348                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5349                                 LOGW("not found AUDIO codec, posting error code to application.\n");
5350
5351                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5352                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5353                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5354                                 LOGW("not found VIDEO codec, posting error code to application.\n");
5355
5356                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5357                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5358                         }
5359
5360                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5361
5362                         MMPLAYER_FREEIF(msg_param.data);
5363
5364                         return MM_ERROR_NONE;
5365                 } else {
5366                         // no any supported codec case
5367                         LOGW("not found any codec, posting error code to application.\n");
5368
5369                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5370                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5371                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5372                         } else {
5373                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5374                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5375                         }
5376
5377                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5378
5379                         MMPLAYER_FREEIF(msg_param.data);
5380                 }
5381         }
5382
5383         MMPLAYER_FLEAVE();
5384
5385         return MM_ERROR_NONE;
5386 }
5387
5388 static void __mmplayer_check_pipeline(mm_player_t* player)
5389 {
5390         GstState element_state = GST_STATE_VOID_PENDING;
5391         GstState element_pending_state = GST_STATE_VOID_PENDING;
5392         gint timeout = 0;
5393         int ret = MM_ERROR_NONE;
5394
5395         if (player->gapless.reconfigure) {
5396                 LOGW("pipeline is under construction.\n");
5397
5398                 MMPLAYER_PLAYBACK_LOCK(player);
5399                 MMPLAYER_PLAYBACK_UNLOCK(player);
5400
5401                 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5402
5403                 /* wait for state transition */
5404                 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5405
5406                 if (ret == GST_STATE_CHANGE_FAILURE)
5407                         LOGE("failed to change pipeline state within %d sec\n", timeout);
5408         }
5409 }
5410
5411 /* NOTE : it should be able to call 'stop' anytime*/
5412 int
5413 _mmplayer_stop(MMHandleType hplayer)
5414 {
5415         mm_player_t* player = (mm_player_t*)hplayer;
5416         int ret = MM_ERROR_NONE;
5417
5418         MMPLAYER_FENTER();
5419
5420         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5421
5422         /* check current state */
5423         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5424
5425         /* check pipline building state */
5426         __mmplayer_check_pipeline(player);
5427         __mmplayer_reset_gapless_state(player);
5428
5429         /* NOTE : application should not wait for EOS after calling STOP */
5430         __mmplayer_cancel_eos_timer(player);
5431
5432         __mmplayer_unrealize_streaming_ext(player);
5433
5434         /* reset */
5435         player->seek_state = MMPLAYER_SEEK_NONE;
5436
5437         /* stop pipeline */
5438         ret = __mmplayer_gst_stop(player);
5439
5440         if (ret != MM_ERROR_NONE)
5441                 LOGE("failed to stop player.\n");
5442
5443         MMPLAYER_FLEAVE();
5444
5445         return ret;
5446 }
5447
5448 int
5449 _mmplayer_pause(MMHandleType hplayer)
5450 {
5451         mm_player_t* player = (mm_player_t*)hplayer;
5452         gint64 pos_nsec = 0;
5453         gboolean async = FALSE;
5454         gint ret = MM_ERROR_NONE;
5455
5456         MMPLAYER_FENTER();
5457
5458         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5459
5460         /* check current state */
5461         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5462
5463         /* check pipline building state */
5464         __mmplayer_check_pipeline(player);
5465
5466         switch (MMPLAYER_CURRENT_STATE(player)) {
5467         case MM_PLAYER_STATE_READY:
5468                 {
5469                         /* check prepare async or not.
5470                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5471                          */
5472                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5473                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5474
5475                         /* Changing back sync of rtspsrc to async */
5476                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5477                                 LOGD("async prepare working mode for rtsp");
5478                                 async = TRUE;
5479                         }
5480                 }
5481                 break;
5482
5483         case MM_PLAYER_STATE_PLAYING:
5484                 {
5485                         /* NOTE : store current point to overcome some bad operation
5486                         *(returning zero when getting current position in paused state) of some
5487                         * elements
5488                         */
5489                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5490                                 LOGW("getting current position failed in paused\n");
5491
5492                         player->last_position = pos_nsec;
5493
5494                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5495                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5496                            This causes problem is position calculation during normal pause resume scenarios also.
5497                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5498                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5499                                 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5500                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5501                         }
5502                 }
5503                 break;
5504         }
5505
5506         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5507                 LOGD("doing async pause in case of ms buff src");
5508                 async = TRUE;
5509         }
5510
5511         /* pause pipeline */
5512         ret = __mmplayer_gst_pause(player, async);
5513
5514         if (ret != MM_ERROR_NONE)
5515                 LOGE("failed to pause player. ret : 0x%x\n", ret);
5516
5517         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5518                 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5519                         LOGE("failed to update display_rotation");
5520         }
5521
5522         MMPLAYER_FLEAVE();
5523
5524         return ret;
5525 }
5526
5527 /* in case of streaming, pause could take long time.*/
5528 int
5529 _mmplayer_abort_pause(MMHandleType hplayer)
5530 {
5531         mm_player_t* player = (mm_player_t*)hplayer;
5532         int ret = MM_ERROR_NONE;
5533
5534         MMPLAYER_FENTER();
5535
5536         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5537                                                 player->pipeline &&
5538                                                 player->pipeline->mainbin,
5539                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5540
5541         LOGD("set the pipeline state to READY");
5542
5543         /* set state to READY */
5544         ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5545                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5546         if (ret != MM_ERROR_NONE) {
5547                 LOGE("fail to change state to READY");
5548                 return MM_ERROR_PLAYER_INTERNAL;
5549         }
5550
5551         LOGD("succeeded in changing state to READY");
5552         return ret;
5553 }
5554
5555
5556 int
5557 _mmplayer_resume(MMHandleType hplayer)
5558 {
5559         mm_player_t* player = (mm_player_t*)hplayer;
5560         int ret = MM_ERROR_NONE;
5561         gboolean async = FALSE;
5562
5563         MMPLAYER_FENTER();
5564
5565         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5566
5567         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5568                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5569                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5570                         return ret;
5571                 }
5572
5573                 /* Changing back sync mode rtspsrc to async */
5574                 LOGD("async resume for rtsp case");
5575                 async = TRUE;
5576         }
5577
5578         /* check current state */
5579         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5580
5581         ret = __mmplayer_gst_resume(player, async);
5582         if (ret != MM_ERROR_NONE)
5583                 LOGE("failed to resume player.\n");
5584
5585         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5586                 LOGD("force resume even during buffering");
5587                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5588         }
5589
5590         MMPLAYER_FLEAVE();
5591
5592         return ret;
5593 }
5594
5595 int
5596 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5597 {
5598         mm_player_t* player = (mm_player_t*)hplayer;
5599         gint64 pos_nsec = 0;
5600         int ret = MM_ERROR_NONE;
5601         int mute = FALSE;
5602         signed long long start = 0, stop = 0;
5603         MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5604         MMPLAYER_FENTER();
5605
5606         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5607         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5608
5609         /* The sound of video is not supported under 0.0 and over 2.0. */
5610         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5611                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5612                         mute = TRUE;
5613         }
5614         _mmplayer_set_mute(hplayer, mute);
5615
5616         if (player->playback_rate == rate)
5617                 return MM_ERROR_NONE;
5618
5619         /* If the position is reached at start potion during fast backward, EOS is posted.
5620          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5621          * */
5622         player->playback_rate = rate;
5623
5624         current_state = MMPLAYER_CURRENT_STATE(player);
5625
5626         if (current_state != MM_PLAYER_STATE_PAUSED)
5627                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5628
5629         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5630
5631         if ((current_state == MM_PLAYER_STATE_PAUSED)
5632                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5633                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5634                 pos_nsec = player->last_position;
5635         }
5636
5637         if (rate >= 0) {
5638                 start = pos_nsec;
5639                 stop = GST_CLOCK_TIME_NONE;
5640         } else {
5641                 start = GST_CLOCK_TIME_NONE;
5642                 stop = pos_nsec;
5643         }
5644
5645         if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5646                                 player->playback_rate,
5647                                 GST_FORMAT_TIME,
5648                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5649                                 GST_SEEK_TYPE_SET, start,
5650                                 GST_SEEK_TYPE_SET, stop)) {
5651                 LOGE("failed to set speed playback\n");
5652                 return MM_ERROR_PLAYER_SEEK;
5653         }
5654
5655         LOGD("succeeded to set speed playback as %0.1f\n", rate);
5656
5657         MMPLAYER_FLEAVE();
5658
5659         return MM_ERROR_NONE;;
5660 }
5661
5662 int
5663 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5664 {
5665         mm_player_t* player = (mm_player_t*)hplayer;
5666         int ret = MM_ERROR_NONE;
5667
5668         MMPLAYER_FENTER();
5669
5670         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5671
5672         /* check pipline building state */
5673         __mmplayer_check_pipeline(player);
5674
5675         ret = __mmplayer_gst_set_position(player, position, FALSE);
5676
5677         MMPLAYER_FLEAVE();
5678
5679         return ret;
5680 }
5681
5682 int
5683 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5684 {
5685         mm_player_t* player = (mm_player_t*)hplayer;
5686         int ret = MM_ERROR_NONE;
5687
5688         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5689
5690         ret = __mmplayer_gst_get_position(player, position);
5691
5692         return ret;
5693 }
5694
5695 int
5696 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5697 {
5698         mm_player_t* player = (mm_player_t*)hplayer;
5699         int ret = MM_ERROR_NONE;
5700
5701         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5702         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5703
5704         *duration = player->duration;
5705         return ret;
5706 }
5707
5708 int
5709 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5710 {
5711         mm_player_t* player = (mm_player_t*)hplayer;
5712         int ret = MM_ERROR_NONE;
5713
5714         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5715
5716         ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5717
5718         return ret;
5719 }
5720
5721 int
5722 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5723 {
5724         mm_player_t* player = (mm_player_t*)hplayer;
5725         int ret = MM_ERROR_NONE;
5726
5727         MMPLAYER_FENTER();
5728
5729         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5730
5731         ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5732
5733         MMPLAYER_FLEAVE();
5734
5735         return ret;
5736 }
5737
5738 static gboolean
5739 __mmplayer_is_midi_type(gchar* str_caps)
5740 {
5741         if ((g_strrstr(str_caps, "audio/midi")) ||
5742                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5743                 (g_strrstr(str_caps, "application/x-smaf")) ||
5744                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5745                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5746                 (g_strrstr(str_caps, "audio/xmf")) ||
5747                 (g_strrstr(str_caps, "audio/mxmf"))) {
5748                 LOGD("midi\n");
5749                 return TRUE;
5750         }
5751
5752         return FALSE;
5753 }
5754
5755 static gboolean
5756 __mmplayer_is_only_mp3_type(gchar *str_caps)
5757 {
5758         if (g_strrstr(str_caps, "application/x-id3") ||
5759                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5760                 return TRUE;
5761         return FALSE;
5762 }
5763
5764 static void
5765 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5766 {
5767         GstStructure* caps_structure = NULL;
5768         gint samplerate = 0;
5769         gint channels = 0;
5770
5771         MMPLAYER_FENTER();
5772         MMPLAYER_RETURN_IF_FAIL(player && caps);
5773
5774         caps_structure = gst_caps_get_structure(caps, 0);
5775
5776         /* set stream information */
5777         gst_structure_get_int(caps_structure, "rate", &samplerate);
5778         mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5779
5780         gst_structure_get_int(caps_structure, "channels", &channels);
5781         mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5782
5783         LOGD("audio samplerate : %d     channels : %d\n", samplerate, channels);
5784 }
5785
5786 static void
5787 __mmplayer_update_content_type_info(mm_player_t* player)
5788 {
5789         MMPLAYER_FENTER();
5790         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5791
5792         if (__mmplayer_is_midi_type(player->type)) {
5793                 player->bypass_audio_effect = TRUE;
5794         } else if (g_strrstr(player->type, "application/x-hls")) {
5795                 /* If it can't know exact type when it parses uri because of redirection case,
5796                  * it will be fixed by typefinder or when doing autoplugging.
5797                  */
5798                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5799                 if (player->streamer) {
5800                         player->streamer->is_adaptive_streaming = TRUE;
5801                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5802                         player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5803                 }
5804         } else if (g_strrstr(player->type, "application/dash+xml")) {
5805                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5806                 if (player->streamer) {
5807                         player->streamer->is_adaptive_streaming = TRUE;
5808                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5809                 }
5810         }
5811
5812         LOGD("uri type : %d", player->profile.uri_type);
5813         MMPLAYER_FLEAVE();
5814 }
5815
5816 void
5817 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5818 GstCaps *caps, gpointer data)
5819 {
5820         mm_player_t* player = (mm_player_t*)data;
5821         GstPad* pad = NULL;
5822
5823         MMPLAYER_FENTER();
5824
5825         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5826
5827         /* store type string */
5828         MMPLAYER_FREEIF(player->type);
5829         player->type = gst_caps_to_string(caps);
5830         if (player->type) {
5831                 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5832                                 player, player->type, probability, gst_caps_get_size(caps));
5833         }
5834
5835         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5836                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5837                 LOGE("not support media format\n");
5838
5839                 if (player->msg_posted == FALSE) {
5840                         MMMessageParamType msg_param;
5841                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5842
5843                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5844                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5845
5846                         /* don't post more if one was sent already */
5847                         player->msg_posted = TRUE;
5848                 }
5849                 return;
5850         }
5851
5852         __mmplayer_update_content_type_info(player);
5853
5854         pad = gst_element_get_static_pad(tf, "src");
5855         if (!pad) {
5856                 LOGE("fail to get typefind src pad.\n");
5857                 return;
5858         }
5859
5860         if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5861                 gboolean async = FALSE;
5862                 LOGE("failed to autoplug %s\n", player->type);
5863
5864                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5865
5866                 if (async && player->msg_posted == FALSE)
5867                         __mmplayer_handle_missed_plugin(player);
5868
5869                 goto DONE;
5870         }
5871
5872 DONE:
5873         gst_object_unref(GST_OBJECT(pad));
5874
5875         MMPLAYER_FLEAVE();
5876
5877         return;
5878 }
5879
5880 GstElement *
5881 __mmplayer_gst_make_decodebin(mm_player_t* player)
5882 {
5883         GstElement *decodebin = NULL;
5884
5885         MMPLAYER_FENTER();
5886
5887         /* create decodebin */
5888         decodebin = gst_element_factory_make("decodebin", NULL);
5889
5890         if (!decodebin) {
5891                 LOGE("fail to create decodebin\n");
5892                 goto ERROR;
5893         }
5894
5895         /* raw pad handling signal */
5896         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5897                                                 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5898
5899         /* no-more-pad pad handling signal */
5900         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5901                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5902
5903         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5904                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5905
5906         /* This signal is emitted when a pad for which there is no further possible
5907            decoding is added to the decodebin.*/
5908         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5909                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5910
5911         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5912            before looking for any elements that can handle that stream.*/
5913         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5914                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5915
5916         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5917            before looking for any elements that can handle that stream.*/
5918         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5919                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5920
5921         /* This signal is emitted once decodebin has finished decoding all the data.*/
5922         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5923                                                 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5924
5925         /* This signal is emitted when a element is added to the bin.*/
5926         __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5927                                                 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5928
5929 ERROR:
5930         return decodebin;
5931 }
5932
5933 static GstElement*
5934 __mmplayer_gst_make_queue2(mm_player_t *player)
5935 {
5936         GstElement* queue2 = NULL;
5937         gint64 dur_bytes = 0L;
5938         guint max_buffer_size_bytes = 0;
5939         MMPlayerGstElement *mainbin = NULL;
5940         MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5941
5942         MMPLAYER_FENTER();
5943         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5944
5945         mainbin = player->pipeline->mainbin;
5946
5947         queue2 = gst_element_factory_make("queue2", "queue2");
5948         if (!queue2) {
5949                 LOGE("failed to create buffering queue element");
5950                 return NULL;
5951         }
5952
5953         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5954                 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5955
5956         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5957
5958         if (dur_bytes > 0) {
5959                 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5960                         type = MUXED_BUFFER_TYPE_FILE;
5961                 } else {
5962                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5963                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5964                 }
5965         } else {
5966                 dur_bytes = 0;
5967         }
5968
5969         /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5970          *                skip the pull mode(file or ring buffering) setting. */
5971         if (!g_strrstr(player->type, "video/mpegts")) {
5972                 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5973                 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5974
5975                 __mm_player_streaming_set_queue2(player->streamer,
5976                                                                                 queue2,
5977                                                                                 FALSE,
5978                                                                                 max_buffer_size_bytes,
5979                                                                                 player->ini.http_buffering_time,
5980                                                                                 1.0,                                                            /* no meaning */
5981                                                                                 player->ini.http_buffering_limit,       /* no meaning */
5982                                                                                 type,
5983                                                                                 player->http_file_buffering_path,
5984                                                                                 (guint64)dur_bytes);
5985         }
5986
5987         return queue2;
5988 }
5989
5990 gboolean
5991 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5992 {
5993         MMPlayerGstElement* mainbin = NULL;
5994         GstElement* decodebin = NULL;
5995         GstElement* queue2 = NULL;
5996         GstPad* sinkpad = NULL;
5997         GstPad* qsrcpad = NULL;
5998         gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5999
6000         MMPLAYER_FENTER();
6001         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6002
6003         mainbin = player->pipeline->mainbin;
6004
6005         if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
6006
6007                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6008                         LOGW("need to check: muxed buffer is not null");
6009                 }
6010
6011                 queue2 = __mmplayer_gst_make_queue2(player);
6012                 if (!queue2) {
6013                         LOGE("failed to make queue2");
6014                         goto ERROR;
6015                 }
6016
6017                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6018                         LOGE("failed to add buffering queue");
6019                         goto ERROR;
6020                 }
6021
6022                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6023                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6024
6025                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6026                         LOGE("failed to link [%s:%s]-[%s:%s]",
6027                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6028                         goto ERROR;
6029                 }
6030
6031                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6032                         LOGE("failed to sync queue2 state with parent");
6033                         goto ERROR;
6034                 }
6035
6036                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6037                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6038
6039                 srcpad = qsrcpad;
6040
6041                 gst_object_unref(GST_OBJECT(sinkpad));
6042                 sinkpad = NULL;
6043         }
6044
6045         /* create decodebin */
6046         decodebin = __mmplayer_gst_make_decodebin(player);
6047         if (!decodebin) {
6048                 LOGE("failed to make decodebin");
6049                 goto ERROR;
6050         }
6051
6052         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6053                 LOGE("failed to add decodebin\n");
6054                 goto ERROR;
6055         }
6056
6057         /* to force caps on the decodebin element and avoid reparsing stuff by
6058         * typefind. It also avoids a deadlock in the way typefind activates pads in
6059         * the state change */
6060         g_object_set(decodebin, "sink-caps", caps, NULL);
6061
6062         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6063
6064         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6065                 LOGE("failed to link [%s:%s]-[%s:%s]",
6066                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6067                 goto ERROR;
6068         }
6069
6070         gst_object_unref(GST_OBJECT(sinkpad));
6071         sinkpad = NULL;
6072
6073         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6074         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6075
6076         /* set decodebin property about buffer in streaming playback. *
6077          * in case of HLS/DASH, it does not need to have big buffer   *
6078          * because it is kind of adaptive streaming.                  */
6079         if (!MMPLAYER_IS_HTTP_PD(player) &&
6080             (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6081             gdouble high_percent = 0.0;
6082
6083                 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6084                 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6085
6086                 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6087                         GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6088
6089                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6090                                                                                         "high-percent", (gint)high_percent,
6091                                                                                         "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6092                                                                                         "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6093                                                                                         "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6094                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6095         }
6096
6097         if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6098                 LOGE("failed to sync decodebin state with parent\n");
6099                 goto ERROR;
6100         }
6101
6102         MMPLAYER_FLEAVE();
6103
6104         return TRUE;
6105
6106 ERROR:
6107
6108         if (sinkpad)
6109                 gst_object_unref(GST_OBJECT(sinkpad));
6110
6111         if (queue2) {
6112                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6113                  * You need to explicitly set elements to the NULL state before
6114                  * dropping the final reference, to allow them to clean up.
6115                  */
6116                 gst_element_set_state(queue2, GST_STATE_NULL);
6117
6118                 /* And, it still has a parent "player".
6119                  * You need to let the parent manage the object instead of unreffing the object directly.
6120                  */
6121                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6122                 gst_object_unref(queue2);
6123                 queue2 = NULL;
6124         }
6125
6126         if (decodebin) {
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(decodebin, 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
6137                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6138                 gst_object_unref(decodebin);
6139                 decodebin = NULL;
6140         }
6141
6142         return FALSE;
6143 }
6144
6145 static int
6146 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6147 {
6148         MMPLAYER_FENTER();
6149
6150         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6151         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6152
6153         LOGD("class : %s, mime : %s \n", factory_class, mime);
6154
6155         /* add missing plugin */
6156         /* NOTE : msl should check missing plugin for image mime type.
6157          * Some motion jpeg clips can have playable audio track.
6158          * So, msl have to play audio after displaying popup written video format not supported.
6159          */
6160         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6161                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6162                         LOGD("not found demuxer\n");
6163                         player->not_found_demuxer = TRUE;
6164                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6165
6166                         goto DONE;
6167                 }
6168         }
6169
6170         if (!g_strrstr(factory_class, "Demuxer")) {
6171                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6172                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6173                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6174
6175                         /* check that clip have multi tracks or not */
6176                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6177                                 LOGD("video plugin is already linked\n");
6178                         } else {
6179                                 LOGW("add VIDEO to missing plugin\n");
6180                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6181                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6182                         }
6183                 } else if (g_str_has_prefix(mime, "audio")) {
6184                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6185                                 LOGD("audio plugin is already linked\n");
6186                         } else {
6187                                 LOGW("add AUDIO to missing plugin\n");
6188                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6189                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6190                         }
6191                 }
6192         }
6193
6194 DONE:
6195         MMPLAYER_FLEAVE();
6196
6197         return MM_ERROR_NONE;
6198 }
6199
6200
6201 static void
6202 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
6203 {
6204         mm_player_t* player = (mm_player_t*)data;
6205
6206         MMPLAYER_FENTER();
6207
6208         MMPLAYER_RETURN_IF_FAIL(player);
6209
6210         /* remove fakesink. */
6211         if (!__mmplayer_gst_remove_fakesink(player,
6212                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6213                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6214                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6215                  * source element are not same. To overcome this situation, this function will called
6216                  * several places and several times. Therefore, this is not an error case.
6217                  */
6218                 return;
6219         }
6220
6221         LOGD("[handle: %p] pipeline has completely constructed", player);
6222
6223         if ((player->ini.async_start) &&
6224                 (player->msg_posted == FALSE) &&
6225                 (player->cmd >= MMPLAYER_COMMAND_START))
6226                 __mmplayer_handle_missed_plugin(player);
6227
6228         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6229 }
6230
6231 static int
6232 __mmplayer_check_profile(void)
6233 {
6234         char *profileName;
6235         static int profile_tv = -1;
6236
6237         if (__builtin_expect(profile_tv != -1, 1))
6238                 return profile_tv;
6239
6240         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6241         switch (*profileName) {
6242         case 't':
6243         case 'T':
6244                 profile_tv = 1;
6245                 break;
6246         default:
6247                 profile_tv = 0;
6248                 break;
6249         }
6250         free(profileName);
6251
6252         return profile_tv;
6253 }
6254
6255 static gboolean
6256 __mmplayer_get_next_uri(mm_player_t *player)
6257 {
6258         MMPlayerParseProfile profile;
6259         gint uri_idx = 0;
6260         guint num_of_list = 0;
6261         char *uri = NULL;
6262
6263         num_of_list = g_list_length(player->uri_info.uri_list);
6264         uri_idx = player->uri_info.uri_idx;
6265
6266         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6267         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6268                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6269                 if (uri == NULL) {
6270                         LOGW("next uri does not exist");
6271                         continue;
6272                 }
6273
6274                 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6275                         LOGE("failed to parse profile");
6276                         continue;
6277                 }
6278
6279                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6280                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6281                         LOGW("uri type is not supported(%d)", profile.uri_type);
6282                         continue;
6283                 }
6284
6285                 LOGD("success to find next uri %d", uri_idx);
6286                 break;
6287         }
6288
6289         if (uri_idx == num_of_list) {
6290                 LOGE("failed to find next uri");
6291                 return FALSE;
6292         }
6293
6294         player->uri_info.uri_idx = uri_idx;
6295         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6296
6297         if (mm_attrs_commit_all(player->attrs)) {
6298                 LOGE("failed to commit");
6299                 return FALSE;
6300         }
6301
6302         SECURE_LOGD("next playback uri: %s", uri);
6303         return TRUE;
6304 }
6305
6306 static gboolean
6307 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6308 {
6309 #define REPEAT_COUNT_INFINITELY -1
6310 #define REPEAT_COUNT_MIN 2
6311
6312         MMHandleType attrs = 0;
6313         gint mode = MM_PLAYER_PD_MODE_NONE;
6314         gint video = 0;
6315         gint count = 0;
6316         gint gapless = 0;
6317         guint num_of_list = 0;
6318         int profile_tv = -1;
6319
6320         MMPLAYER_FENTER();
6321
6322         LOGD("checking for gapless play option");
6323
6324         if (player->pipeline->textbin) {
6325                 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6326                 goto ERROR;
6327         }
6328
6329         attrs = MMPLAYER_GET_ATTRS(player);
6330         if (!attrs) {
6331                 LOGE("fail to get attributes.\n");
6332                 goto ERROR;
6333         }
6334
6335         mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6336
6337         /* gapless playback is not supported in case of video at TV profile. */
6338         profile_tv = __mmplayer_check_profile();
6339         if (profile_tv && video) {
6340                 LOGW("not support video gapless playback");
6341                 goto ERROR;
6342         }
6343
6344         if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6345                 if (mode == TRUE) {
6346                         LOGW("pd mode\n");
6347                         goto ERROR;
6348                 }
6349         }
6350
6351         if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6352                 LOGE("failed to get play count");
6353
6354         if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6355                 LOGE("failed to get gapless mode");
6356
6357         /* check repeat count in case of audio */
6358         if (!gapless &&
6359                 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6360                 LOGW("gapless is disabled");
6361                 goto ERROR;
6362         }
6363
6364         num_of_list = g_list_length(player->uri_info.uri_list);
6365
6366         LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6367
6368         if (num_of_list == 0) {
6369                 /* audio looping path */
6370                 if (count >= REPEAT_COUNT_MIN) {
6371                         /* decrease play count */
6372                         /* we succeeded to rewind. update play count and then wait for next EOS */
6373                         count--;
6374
6375                         mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6376
6377                         /* commit attribute */
6378                         if (mm_attrs_commit_all(attrs))
6379                                 LOGE("failed to commit attribute");
6380                 } else if (count != REPEAT_COUNT_INFINITELY) {
6381                         LOGD("there is no next uri and no repeat");
6382                         goto ERROR;
6383                 }
6384
6385                 LOGD("looping cnt %d", count);
6386         } else {
6387                 /* gapless playback path */
6388                 if (!__mmplayer_get_next_uri(player)) {
6389                         LOGE("failed to get next uri");
6390                         goto ERROR;
6391                 }
6392         }
6393
6394         return TRUE;
6395
6396 ERROR:
6397         LOGE("unable to play gapless path. EOS will be posted soon");
6398         return FALSE;
6399 }
6400
6401 static void
6402 __mmplayer_initialize_gapless_play(mm_player_t *player)
6403 {
6404         int i;
6405
6406         MMPLAYER_FENTER();
6407
6408         player->smooth_streaming = FALSE;
6409         player->videodec_linked = 0;
6410         player->audiodec_linked = 0;
6411         player->textsink_linked = 0;
6412         player->is_external_subtitle_present = FALSE;
6413         player->is_external_subtitle_added_now = FALSE;
6414         player->not_supported_codec = MISSING_PLUGIN_NONE;
6415         player->can_support_codec = FOUND_PLUGIN_NONE;
6416         player->pending_seek.is_pending = FALSE;
6417         player->pending_seek.pos = 0;
6418         player->msg_posted = FALSE;
6419         player->has_many_types = FALSE;
6420         player->no_more_pad = FALSE;
6421         player->not_found_demuxer = 0;
6422         player->seek_state = MMPLAYER_SEEK_NONE;
6423         player->is_subtitle_force_drop = FALSE;
6424         player->play_subtitle = FALSE;
6425         player->adjust_subtitle_pos = 0;
6426
6427         player->total_bitrate = 0;
6428         player->total_maximum_bitrate = 0;
6429
6430         __mmplayer_track_initialize(player);
6431         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6432
6433         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6434                 player->bitrate[i] = 0;
6435                 player->maximum_bitrate[i] = 0;
6436         }
6437
6438         if (player->v_stream_caps) {
6439                 gst_caps_unref(player->v_stream_caps);
6440                 player->v_stream_caps = NULL;
6441         }
6442
6443         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6444
6445         /* clean found parsers */
6446         if (player->parsers) {
6447                 GList *parsers = player->parsers;
6448                 for (; parsers; parsers = g_list_next(parsers)) {
6449                         gchar *name = parsers->data;
6450                         MMPLAYER_FREEIF(name);
6451                 }
6452                 g_list_free(player->parsers);
6453                 player->parsers = NULL;
6454         }
6455
6456         /* clean found audio decoders */
6457         if (player->audio_decoders) {
6458                 GList *a_dec = player->audio_decoders;
6459                 for (; a_dec; a_dec = g_list_next(a_dec)) {
6460                         gchar *name = a_dec->data;
6461                         MMPLAYER_FREEIF(name);
6462                 }
6463                 g_list_free(player->audio_decoders);
6464                 player->audio_decoders = NULL;
6465         }
6466
6467         MMPLAYER_FLEAVE();
6468 }
6469
6470 static void
6471 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6472 {
6473         MMPlayerGstElement *mainbin = NULL;
6474         MMMessageParamType msg_param = {0,};
6475         GstElement *element = NULL;
6476         MMHandleType attrs = 0;
6477         char *uri = NULL;
6478         enum MainElementID elem_idx = MMPLAYER_M_NUM;
6479
6480         MMPLAYER_FENTER();
6481
6482         if (!player || !player->pipeline || !player->pipeline->mainbin) {
6483                 LOGE("player is not initialized");
6484                 goto ERROR;
6485         }
6486
6487         mainbin = player->pipeline->mainbin;
6488         msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6489
6490         attrs = MMPLAYER_GET_ATTRS(player);
6491         if (!attrs) {
6492                 LOGE("fail to get attributes");
6493                 goto ERROR;
6494         }
6495
6496         /* Initialize Player values */
6497         __mmplayer_initialize_gapless_play(player);
6498
6499         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6500
6501         if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6502                 LOGE("failed to parse profile");
6503                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6504                 goto ERROR;
6505         }
6506
6507         if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6508                 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6509                 LOGE("dash or hls is not supportable");
6510                 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6511                 goto ERROR;
6512         }
6513
6514         element = __mmplayer_gst_create_source(player);
6515         if (!element) {
6516                 LOGE("no source element was created");
6517                 goto ERROR;
6518         }
6519
6520         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6521                 LOGE("failed to add source element to pipeline");
6522                 gst_object_unref(GST_OBJECT(element));
6523                 element = NULL;
6524                 goto ERROR;
6525         }
6526
6527         /* take source element */
6528         mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6529         mainbin[MMPLAYER_M_SRC].gst = element;
6530
6531         element = NULL;
6532
6533         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6534                 if (player->streamer == NULL) {
6535                         player->streamer = __mm_player_streaming_create();
6536                         __mm_player_streaming_initialize(player->streamer);
6537                 }
6538
6539                 elem_idx = MMPLAYER_M_TYPEFIND;
6540                 element = gst_element_factory_make("typefind", "typefinder");
6541                 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6542                         MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6543         } else {
6544                 elem_idx = MMPLAYER_M_AUTOPLUG;
6545                 element = __mmplayer_gst_make_decodebin(player);
6546         }
6547
6548         /* check autoplug element is OK */
6549         if (!element) {
6550                 LOGE("can not create element(%d)", elem_idx);
6551                 goto ERROR;
6552         }
6553
6554         if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6555                 LOGE("failed to add sinkbin to pipeline");
6556                 gst_object_unref(GST_OBJECT(element));
6557                 element = NULL;
6558                 goto ERROR;
6559         }
6560
6561         mainbin[elem_idx].id = elem_idx;
6562         mainbin[elem_idx].gst = element;
6563
6564         if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6565                 LOGE("Failed to link src - autoplug(or typefind)");
6566                 goto ERROR;
6567         }
6568
6569         if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6570                 LOGE("Failed to change state of src element");
6571                 goto ERROR;
6572         }
6573
6574         if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6575                 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6576                         LOGE("Failed to change state of decodebin");
6577                         goto ERROR;
6578                 }
6579         } else {
6580                 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6581                         LOGE("Failed to change state of src element");
6582                         goto ERROR;
6583                 }
6584         }
6585
6586         player->gapless.stream_changed = TRUE;
6587         player->gapless.running = TRUE;
6588         MMPLAYER_FLEAVE();
6589         return;
6590
6591 ERROR:
6592         if (player) {
6593                 MMPLAYER_PLAYBACK_UNLOCK(player);
6594
6595                 if (!player->msg_posted) {
6596                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6597                         player->msg_posted = TRUE;
6598                 }
6599         }
6600         return;
6601 }
6602
6603 static gboolean
6604 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6605 {
6606         mm_player_selector_t *selector = &player->selector[type];
6607         MMPlayerGstElement *sinkbin = NULL;
6608         enum MainElementID selectorId = MMPLAYER_M_NUM;
6609         enum MainElementID sinkId = MMPLAYER_M_NUM;
6610         GstPad *srcpad = NULL;
6611         GstPad *sinkpad = NULL;
6612         gboolean send_notice = FALSE;
6613
6614         MMPLAYER_FENTER();
6615         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6616
6617         LOGD("type %d", type);
6618
6619         switch (type) {
6620         case MM_PLAYER_TRACK_TYPE_AUDIO:
6621                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6622                 sinkId = MMPLAYER_A_BIN;
6623                 sinkbin = player->pipeline->audiobin;
6624                 break;
6625         case MM_PLAYER_TRACK_TYPE_VIDEO:
6626                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6627                 sinkId = MMPLAYER_V_BIN;
6628                 sinkbin = player->pipeline->videobin;
6629                 send_notice = TRUE;
6630                 break;
6631         case MM_PLAYER_TRACK_TYPE_TEXT:
6632                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6633                 sinkId = MMPLAYER_T_BIN;
6634                 sinkbin = player->pipeline->textbin;
6635                 break;
6636         default:
6637                 LOGE("requested type is not supportable");
6638                 return FALSE;
6639                 break;
6640         }
6641
6642         if (player->pipeline->mainbin[selectorId].gst) {
6643                 gint n;
6644
6645                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6646
6647                 if (selector->event_probe_id != 0)
6648                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6649                 selector->event_probe_id = 0;
6650
6651                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6652                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6653
6654                         if (srcpad && sinkpad) {
6655                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6656                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6657                                 gst_pad_unlink(srcpad, sinkpad);
6658
6659                                 /* send custom event to sink pad to handle it at video sink */
6660                                 if (send_notice) {
6661                                         LOGD("send custom event to sinkpad");
6662                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6663                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6664                                         gst_pad_send_event(sinkpad, event);
6665                                 }
6666                         }
6667
6668                         gst_object_unref(sinkpad);
6669                         sinkpad = NULL;
6670                 }
6671                 gst_object_unref(srcpad);
6672                 srcpad = NULL;
6673
6674                 LOGD("selector release");
6675
6676                 /* release and unref requests pad from the selector */
6677                 for (n = 0; n < selector->channels->len; n++) {
6678                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6679                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6680                 }
6681                 g_ptr_array_set_size(selector->channels, 0);
6682
6683                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6684                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6685
6686                 player->pipeline->mainbin[selectorId].gst = NULL;
6687                 selector = NULL;
6688         }
6689
6690         return TRUE;
6691 }
6692
6693 static void
6694 __mmplayer_deactivate_old_path(mm_player_t *player)
6695 {
6696         MMPLAYER_FENTER();
6697         MMPLAYER_RETURN_IF_FAIL(player);
6698
6699         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6700                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6701                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6702                 LOGE("deactivate selector error");
6703                 goto ERROR;
6704         }
6705
6706         __mmplayer_track_destroy(player);
6707         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6708
6709         if (player->streamer) {
6710                 __mm_player_streaming_deinitialize(player->streamer);
6711                 __mm_player_streaming_destroy(player->streamer);
6712                 player->streamer = NULL;
6713         }
6714
6715         MMPLAYER_PLAYBACK_LOCK(player);
6716         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6717
6718         MMPLAYER_FLEAVE();
6719         return;
6720
6721 ERROR:
6722
6723         if (!player->msg_posted) {
6724                 MMMessageParamType msg = {0,};
6725
6726                 /*post error*/
6727                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6728                 LOGE("gapless_uri_play> deactivate error");
6729
6730                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6731                 player->msg_posted = TRUE;
6732         }
6733         return;
6734 }
6735
6736 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6737 {
6738         int result = MM_ERROR_NONE;
6739         mm_player_t* player = (mm_player_t*) hplayer;
6740         MMPLAYER_FENTER();
6741
6742         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6743
6744         if (file_path) {
6745                 player->http_file_buffering_path = (gchar*)file_path;
6746                 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6747         }
6748         MMPLAYER_FLEAVE();
6749         return result;
6750 }
6751
6752 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6753 {
6754         int result = MM_ERROR_NONE;
6755         mm_player_t* player = (mm_player_t*) hplayer;
6756         MMPLAYER_FENTER();
6757
6758         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6759
6760         mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6761         if (mm_attrs_commit_all(player->attrs)) {
6762                 LOGE("failed to commit the original uri.\n");
6763                 result = MM_ERROR_PLAYER_INTERNAL;
6764         } else {
6765                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6766                         LOGE("failed to add the original uri in the uri list.\n");
6767         }
6768
6769         MMPLAYER_FLEAVE();
6770         return result;
6771 }
6772
6773 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6774 {
6775         mm_player_t* player = (mm_player_t*) hplayer;
6776         guint num_of_list = 0;
6777
6778         MMPLAYER_FENTER();
6779
6780         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6781         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6782
6783         if (player->pipeline && player->pipeline->textbin) {
6784                 LOGE("subtitle path is enabled.\n");
6785                 return MM_ERROR_PLAYER_INVALID_STATE;
6786         }
6787
6788         num_of_list = g_list_length(player->uri_info.uri_list);
6789
6790         if (is_first_path == TRUE) {
6791                 if (num_of_list == 0) {
6792                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6793                         LOGD("add original path : %s", uri);
6794                 } else {
6795                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6796                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6797
6798                         LOGD("change original path : %s", uri);
6799                 }
6800         } else {
6801                 MMHandleType attrs = 0;
6802                 attrs = MMPLAYER_GET_ATTRS(player);
6803
6804                 if (num_of_list == 0) {
6805                         char *original_uri = NULL;
6806
6807                         if (attrs) {
6808                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6809
6810                                 if (!original_uri) {
6811                                         LOGE("there is no original uri.");
6812                                         return MM_ERROR_PLAYER_INVALID_STATE;
6813                                 }
6814
6815                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6816                                 player->uri_info.uri_idx = 0;
6817
6818                                 LOGD("add original path at first : %s(%d)", original_uri);
6819                         }
6820                 }
6821
6822                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6823                 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6824         }
6825
6826         MMPLAYER_FLEAVE();
6827         return MM_ERROR_NONE;
6828 }
6829
6830 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6831 {
6832         mm_player_t* player = (mm_player_t*) hplayer;
6833         char *next_uri = NULL;
6834         guint num_of_list = 0;
6835
6836         MMPLAYER_FENTER();
6837         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6838
6839         num_of_list = g_list_length(player->uri_info.uri_list);
6840
6841         if (num_of_list > 0) {
6842                 gint uri_idx = player->uri_info.uri_idx;
6843
6844                 if (uri_idx < num_of_list-1)
6845                         uri_idx++;
6846                 else
6847                         uri_idx = 0;
6848
6849                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6850                 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6851
6852                 *uri = g_strdup(next_uri);
6853         }
6854
6855         MMPLAYER_FLEAVE();
6856         return MM_ERROR_NONE;
6857 }
6858
6859 static void
6860 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad* pad,
6861 GstCaps *caps, gpointer data)
6862 {
6863         mm_player_t* player = (mm_player_t*)data;
6864         const gchar* klass = NULL;
6865         const gchar* mime = NULL;
6866         gchar* caps_str = NULL;
6867
6868         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6869         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6870         caps_str = gst_caps_to_string(caps);
6871
6872         LOGW("unknown type of caps : %s from %s",
6873                                         caps_str, GST_ELEMENT_NAME(elem));
6874
6875         MMPLAYER_FREEIF(caps_str);
6876
6877         /* There is no available codec. */
6878         __mmplayer_check_not_supported_codec(player, klass, mime);
6879 }
6880
6881 static gboolean
6882 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad* pad,
6883 GstCaps * caps,  gpointer data)
6884 {
6885         mm_player_t* player = (mm_player_t*)data;
6886         const char* mime = NULL;
6887         gboolean ret = TRUE;
6888
6889         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6890         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6891
6892         if (g_str_has_prefix(mime, "audio")) {
6893                 GstStructure* caps_structure = NULL;
6894                 gint samplerate = 0;
6895                 gint channels = 0;
6896                 gchar *caps_str = NULL;
6897
6898                 caps_structure = gst_caps_get_structure(caps, 0);
6899                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6900                 gst_structure_get_int(caps_structure, "channels", &channels);
6901
6902                 if ((channels > 0 && samplerate == 0)) {
6903                         LOGD("exclude audio...");
6904                         ret = FALSE;
6905                 }
6906
6907                 caps_str = gst_caps_to_string(caps);
6908                 /* set it directly because not sent by TAG */
6909                 if (g_strrstr(caps_str, "mobile-xmf"))
6910                         mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6911                 MMPLAYER_FREEIF(caps_str);
6912         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6913                 MMMessageParamType msg_param;
6914                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6915                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6916                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6917                 LOGD("video file is not supported on this device");
6918                 ret = FALSE;
6919         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6920                 LOGD("already video linked");
6921                 ret = FALSE;
6922         } else {
6923                 LOGD("found new stream");
6924         }
6925
6926         return ret;
6927 }
6928
6929 static int
6930 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6931 {
6932         int ret = MM_ERROR_NONE;
6933         int idx = 0;
6934         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6935
6936         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6937                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6938
6939                 LOGD("audio codec type: %d", codec_type);
6940                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6941                         /* sw codec will be skipped */
6942                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6943                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6944                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6945                                         ret = MM_ERROR_PLAYER_INTERNAL;
6946                                         goto DONE;
6947                                 }
6948                         }
6949                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6950                         /* hw codec will be skipped */
6951                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
6952                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6953                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6954                                 ret = MM_ERROR_PLAYER_INTERNAL;
6955                                 goto DONE;
6956                         }
6957                 }
6958
6959                 /* set stream information */
6960                 if (!player->audiodec_linked)
6961                         __mmplayer_set_audio_attrs(player, caps);
6962
6963                 /* update codec info */
6964                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6965                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6966                 player->audiodec_linked = 1;
6967
6968         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6969
6970                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6971
6972                 LOGD("video codec type: %d", codec_type);
6973                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6974                         /* sw codec is skipped */
6975                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6976                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6977                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6978                                         ret = MM_ERROR_PLAYER_INTERNAL;
6979                                         goto DONE;
6980                                 }
6981                         }
6982                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6983                         /* hw codec is skipped */
6984                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6985                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6986                                 ret = MM_ERROR_PLAYER_INTERNAL;
6987                                 goto DONE;
6988                         }
6989                 }
6990
6991                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6992                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6993
6994                         /* mark video decoder for acquire */
6995                         if (player->video_decoder_resource == NULL) {
6996                                 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6997                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6998                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6999                                                 &player->video_decoder_resource)
7000                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
7001                                         LOGE("could not mark video_decoder resource for acquire");
7002                                         ret = MM_ERROR_PLAYER_INTERNAL;
7003                                         goto DONE;
7004                                 }
7005                         } else {
7006                                 LOGW("video decoder resource is already acquired, skip it.");
7007                                 ret = MM_ERROR_PLAYER_INTERNAL;
7008                                 goto DONE;
7009                         }
7010
7011                         player->interrupted_by_resource = FALSE;
7012                         /* acquire resources for video playing */
7013                         if (mm_resource_manager_commit(player->resource_manager)
7014                                         != MM_RESOURCE_MANAGER_ERROR_NONE) {
7015                                 LOGE("could not acquire resources for video decoding\n");
7016                                 ret = MM_ERROR_PLAYER_INTERNAL;
7017                                 goto DONE;
7018                         }
7019                 }
7020
7021                 /* update codec info */
7022                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7023                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7024                 player->videodec_linked = 1;
7025         }
7026
7027 DONE:
7028         return ret;
7029 }
7030
7031 gint
7032 __mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad* pad,
7033 GstCaps* caps, GstElementFactory* factory, gpointer data)
7034 {
7035         /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7036          We are defining our own and will be removed when it actually exposed */
7037         typedef enum {
7038                 GST_AUTOPLUG_SELECT_TRY,
7039                 GST_AUTOPLUG_SELECT_EXPOSE,
7040                 GST_AUTOPLUG_SELECT_SKIP
7041         } GstAutoplugSelectResult;
7042
7043         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7044         mm_player_t* player = (mm_player_t*)data;
7045
7046         gchar* factory_name = NULL;
7047         gchar* caps_str = NULL;
7048         const gchar* klass = NULL;
7049         gint idx = 0;
7050
7051         factory_name = GST_OBJECT_NAME(factory);
7052         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7053         caps_str = gst_caps_to_string(caps);
7054
7055         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7056
7057         /* store type string */
7058         if (player->type == NULL) {
7059                 player->type = gst_caps_to_string(caps);
7060                 __mmplayer_update_content_type_info(player);
7061         }
7062
7063         /* filtering exclude keyword */
7064         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7065                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7066                         LOGW("skipping [%s] by exculde keyword [%s]",
7067                                         factory_name, player->ini.exclude_element_keyword[idx]);
7068
7069                         result = GST_AUTOPLUG_SELECT_SKIP;
7070                         goto DONE;
7071                 }
7072         }
7073
7074         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7075                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7076                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7077                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7078                         result = GST_AUTOPLUG_SELECT_SKIP;
7079                         goto DONE;
7080                 }
7081         }
7082
7083         /* exclude webm format */
7084         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7085          * because webm format is not supportable.
7086          * If webm is disabled in "autoplug-continue", there is no state change
7087          * failure or error because the decodebin will expose the pad directly.
7088          * It make MSL invoke _prepare_async_callback.
7089          * So, we need to disable webm format in "autoplug-select" */
7090         if (caps_str && strstr(caps_str, "webm")) {
7091                 LOGW("webm is not supported");
7092                 result = GST_AUTOPLUG_SELECT_SKIP;
7093                 goto DONE;
7094         }
7095
7096         /* check factory class for filtering */
7097         /* NOTE : msl don't need to use image plugins.
7098          * So, those plugins should be skipped for error handling.
7099          */
7100         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7101                 LOGD("skipping [%s] by not required\n", factory_name);
7102                 result = GST_AUTOPLUG_SELECT_SKIP;
7103                 goto DONE;
7104         }
7105
7106         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7107                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7108                 // TO CHECK : subtitle if needed, add subparse exception.
7109                 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7110                 result = GST_AUTOPLUG_SELECT_SKIP;
7111                 goto DONE;
7112         }
7113
7114         if (g_strrstr(factory_name, "mpegpsdemux")) {
7115                 LOGD("skipping PS container - not support\n");
7116                 result = GST_AUTOPLUG_SELECT_SKIP;
7117                 goto DONE;
7118         }
7119
7120         if (g_strrstr(factory_name, "mssdemux"))
7121                 player->smooth_streaming = TRUE;
7122
7123         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7124                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7125                 gint stype = 0;
7126                 gint width = 0;
7127                 GstStructure *str = NULL;
7128                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7129
7130                 /* don't make video because of not required */
7131                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7132                         (!player->set_mode.media_packet_video_stream)) {
7133                         LOGD("no need video decoding, expose pad");
7134                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7135                         goto DONE;
7136                 }
7137
7138                 /* get w/h for omx state-tune */
7139                 /* FIXME: deprecated? */
7140                 str = gst_caps_get_structure(caps, 0);
7141                 gst_structure_get_int(str, "width", &width);
7142
7143                 if (width != 0) {
7144                         if (player->v_stream_caps) {
7145                                 gst_caps_unref(player->v_stream_caps);
7146                                 player->v_stream_caps = NULL;
7147                         }
7148
7149                         player->v_stream_caps = gst_caps_copy(caps);
7150                         LOGD("take caps for video state tune");
7151                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7152                 }
7153         }
7154
7155         if (g_strrstr(klass, "Codec/Decoder")) {
7156                 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7157                         LOGD("skipping %s codec", factory_name);
7158                         result = GST_AUTOPLUG_SELECT_SKIP;
7159                         goto DONE;
7160                 }
7161         }
7162
7163 DONE:
7164         MMPLAYER_FREEIF(caps_str);
7165
7166         return result;
7167 }
7168
7169 static void
7170 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad* new_pad,
7171 gpointer data)
7172 {
7173         //mm_player_t* player = (mm_player_t*)data;
7174         GstCaps* caps = NULL;
7175
7176         LOGD("[Decodebin2] pad-removed signal\n");
7177
7178         caps = gst_pad_query_caps(new_pad, NULL);
7179         if (caps) {
7180                 gchar* caps_str = NULL;
7181                 caps_str = gst_caps_to_string(caps);
7182
7183                 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7184
7185                 MMPLAYER_FREEIF(caps_str);
7186                 gst_caps_unref(caps);
7187         }
7188 }
7189
7190 static void
7191 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7192 {
7193         mm_player_t* player = (mm_player_t*)data;
7194         GstIterator *iter = NULL;
7195         GValue item = { 0, };
7196         GstPad *pad = NULL;
7197         gboolean done = FALSE;
7198         gboolean is_all_drained = TRUE;
7199
7200         MMPLAYER_FENTER();
7201         MMPLAYER_RETURN_IF_FAIL(player);
7202
7203         LOGD("__mmplayer_gst_decode_drained");
7204
7205         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7206                 LOGW("Fail to get cmd lock");
7207                 return;
7208         }
7209
7210         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7211                 !__mmplayer_verify_gapless_play_path(player)) {
7212                 LOGD("decoding is finished.");
7213                 __mmplayer_reset_gapless_state(player);
7214                 MMPLAYER_CMD_UNLOCK(player);
7215                 return;
7216         }
7217
7218         player->gapless.reconfigure = TRUE;
7219
7220         /* check decodebin src pads whether they received EOS or not */
7221         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7222
7223         while (!done) {
7224                 switch (gst_iterator_next(iter, &item)) {
7225                 case GST_ITERATOR_OK:
7226                         pad = g_value_get_object(&item);
7227                         if (pad && !GST_PAD_IS_EOS(pad)) {
7228                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7229                                 is_all_drained = FALSE;
7230                                 break;
7231                         }
7232                         g_value_reset(&item);
7233                         break;
7234                 case GST_ITERATOR_RESYNC:
7235                         gst_iterator_resync(iter);
7236                         break;
7237                 case GST_ITERATOR_ERROR:
7238                 case GST_ITERATOR_DONE:
7239                         done = TRUE;
7240                         break;
7241                 }
7242         }
7243         g_value_unset(&item);
7244         gst_iterator_free(iter);
7245
7246         if (!is_all_drained) {
7247                 LOGD("Wait util the all pads get EOS.");
7248                 MMPLAYER_CMD_UNLOCK(player);
7249                 MMPLAYER_FLEAVE();
7250                 return;
7251         }
7252
7253         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7254         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7255
7256         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7257         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7258         __mmplayer_deactivate_old_path(player);
7259         MMPLAYER_CMD_UNLOCK(player);
7260
7261         MMPLAYER_FLEAVE();
7262 }
7263
7264 void
7265 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7266 {
7267         mm_player_t* player = (mm_player_t*)data;
7268         const gchar* klass = NULL;
7269         gchar* factory_name = NULL;
7270
7271         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7272         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7273
7274         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7275
7276         if (__mmplayer_add_dump_buffer_probe(player, element))
7277                 LOGD("add buffer probe");
7278
7279         //<-
7280         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7281                 gchar* selected = NULL;
7282                 selected = g_strdup(GST_ELEMENT_NAME(element));
7283                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7284         }
7285         //-> temp code
7286
7287         if (g_strrstr(klass, "Parser")) {
7288                 gchar* selected = NULL;
7289
7290                 selected = g_strdup(factory_name);
7291                 player->parsers = g_list_append(player->parsers, selected);
7292         }
7293
7294         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7295                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7296                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7297
7298                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7299                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7300
7301                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7302                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7303                                                 "max-video-width", player->adaptive_info.limit.width,
7304                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7305
7306         } else if (g_strrstr(klass, "Demuxer")) {
7307                 //LOGD("plugged element is demuxer. take it");
7308                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7309                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7310         }
7311
7312         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7313                 int surface_type = 0;
7314
7315                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7316         }
7317
7318         // to support trust-zone only
7319         if (g_strrstr(factory_name, "asfdemux")) {
7320                 LOGD("set file-location %s\n", player->profile.uri);
7321                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7322         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7323                 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7324                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7325         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7326                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7327                         (__mmplayer_is_only_mp3_type(player->type))) {
7328                         LOGD("[mpegaudioparse] set streaming pull mode.");
7329                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7330                 }
7331         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7332                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7333         }
7334
7335         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7336                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7337                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7338
7339                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7340                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7341
7342                 if (!MMPLAYER_IS_HTTP_PD(player) &&
7343                         ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7344                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7345                         (MMPLAYER_IS_DASH_STREAMING(player)))) {
7346                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7347                         __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7348                         __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7349                 }
7350
7351         }
7352
7353         return;
7354 }
7355
7356 static void
7357 __mmplayer_release_misc(mm_player_t* player)
7358 {
7359         int i;
7360         bool cur_mode = player->set_mode.rich_audio;
7361         MMPLAYER_FENTER();
7362
7363         MMPLAYER_RETURN_IF_FAIL(player);
7364
7365         player->video_stream_cb = NULL;
7366         player->video_stream_cb_user_param = NULL;
7367         player->video_stream_prerolled = FALSE;
7368
7369         player->audio_stream_render_cb = NULL;
7370         player->audio_stream_cb_user_param = NULL;
7371         player->audio_stream_sink_sync = false;
7372
7373         player->video_stream_changed_cb = NULL;
7374         player->video_stream_changed_cb_user_param = NULL;
7375
7376         player->audio_stream_changed_cb = NULL;
7377         player->audio_stream_changed_cb_user_param = NULL;
7378
7379         player->sent_bos = FALSE;
7380         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7381
7382         player->seek_state = MMPLAYER_SEEK_NONE;
7383
7384         player->total_bitrate = 0;
7385         player->total_maximum_bitrate = 0;
7386
7387         player->not_found_demuxer = 0;
7388
7389         player->last_position = 0;
7390         player->duration = 0;
7391         player->http_content_size = 0;
7392         player->not_supported_codec = MISSING_PLUGIN_NONE;
7393         player->can_support_codec = FOUND_PLUGIN_NONE;
7394         player->pending_seek.is_pending = FALSE;
7395         player->pending_seek.pos = 0;
7396         player->msg_posted = FALSE;
7397         player->has_many_types = FALSE;
7398         player->is_subtitle_force_drop = FALSE;
7399         player->play_subtitle = FALSE;
7400         player->adjust_subtitle_pos = 0;
7401         player->last_multiwin_status = FALSE;
7402         player->has_closed_caption = FALSE;
7403         player->set_mode.media_packet_video_stream = false;
7404         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7405         memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7406         /* recover mode */
7407         player->set_mode.rich_audio = cur_mode;
7408
7409         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7410                 player->bitrate[i] = 0;
7411                 player->maximum_bitrate[i] = 0;
7412         }
7413
7414         MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7415
7416         /* remove media stream cb(appsrc cb) */
7417         for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7418                 player->media_stream_buffer_status_cb[i] = NULL;
7419                 player->media_stream_seek_data_cb[i] = NULL;
7420                 player->buffer_cb_user_param[i] = NULL;
7421                 player->seek_cb_user_param[i] = NULL;
7422         }
7423         MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7424
7425         /* free memory related to audio effect */
7426         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7427
7428         if (player->adaptive_info.var_list) {
7429                 g_list_free_full(player->adaptive_info.var_list, g_free);
7430                 player->adaptive_info.var_list = NULL;
7431         }
7432
7433         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7434         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7435         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7436
7437         /* Reset video360 settings to their defaults in case if the pipeline is to be
7438          * re-created.
7439          * */
7440         player->video360_metadata.is_spherical = -1;
7441         player->is_openal_plugin_used = FALSE;
7442
7443         player->is_content_spherical = FALSE;
7444         player->is_video360_enabled = TRUE;
7445         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7446         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7447         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7448         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7449         player->video360_zoom = 1.0f;
7450         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7451         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7452
7453         player->sound.rg_enable = false;
7454
7455         __mmplayer_initialize_video_roi(player);
7456         MMPLAYER_FLEAVE();
7457 }
7458
7459 static void
7460 __mmplayer_release_misc_post(mm_player_t* player)
7461 {
7462         char *original_uri = NULL;
7463         MMPLAYER_FENTER();
7464
7465         /* player->pipeline is already released before. */
7466
7467         MMPLAYER_RETURN_IF_FAIL(player);
7468
7469         mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7470
7471         /* clean found parsers */
7472         if (player->parsers) {
7473                 GList *parsers = player->parsers;
7474                 for (; parsers; parsers = g_list_next(parsers)) {
7475                         gchar *name = parsers->data;
7476                         MMPLAYER_FREEIF(name);
7477                 }
7478                 g_list_free(player->parsers);
7479                 player->parsers = NULL;
7480         }
7481
7482         /* clean found audio decoders */
7483         if (player->audio_decoders) {
7484                 GList *a_dec = player->audio_decoders;
7485                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7486                         gchar *name = a_dec->data;
7487                         MMPLAYER_FREEIF(name);
7488                 }
7489                 g_list_free(player->audio_decoders);
7490                 player->audio_decoders = NULL;
7491         }
7492
7493         /* clean the uri list except original uri */
7494         if (player->uri_info.uri_list) {
7495                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7496
7497                 if (player->attrs) {
7498                         mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7499                         LOGD("restore original uri = %s\n", original_uri);
7500
7501                         if (mm_attrs_commit_all(player->attrs))
7502                                 LOGE("failed to commit the original uri.\n");
7503                 }
7504
7505                 GList *uri_list = player->uri_info.uri_list;
7506                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7507                         gchar *uri = uri_list->data;
7508                         MMPLAYER_FREEIF(uri);
7509                 }
7510                 g_list_free(player->uri_info.uri_list);
7511                 player->uri_info.uri_list = NULL;
7512         }
7513
7514         /* clear the audio stream buffer list */
7515         __mmplayer_audio_stream_clear_buffer(player, FALSE);
7516
7517         /* clear the video stream bo list */
7518         __mmplayer_video_stream_destroy_bo_list(player);
7519         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7520
7521         if (player->profile.input_mem.buf) {
7522                 free(player->profile.input_mem.buf);
7523                 player->profile.input_mem.buf = NULL;
7524         }
7525         player->profile.input_mem.len = 0;
7526         player->profile.input_mem.offset = 0;
7527
7528         player->uri_info.uri_idx = 0;
7529         MMPLAYER_FLEAVE();
7530 }
7531
7532 gboolean
7533 __mmplayer_check_subtitle(mm_player_t* player)
7534 {
7535         MMHandleType attrs = 0;
7536         char *subtitle_uri = NULL;
7537
7538         MMPLAYER_FENTER();
7539
7540         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7541
7542         /* get subtitle attribute */
7543         attrs = MMPLAYER_GET_ATTRS(player);
7544         if (!attrs)
7545                 return FALSE;
7546
7547         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7548         if (!subtitle_uri || !strlen(subtitle_uri))
7549                 return FALSE;
7550
7551         SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7552         player->is_external_subtitle_present = TRUE;
7553
7554         MMPLAYER_FLEAVE();
7555
7556         return TRUE;
7557 }
7558
7559 void
7560 __mmplayer_cancel_eos_timer(mm_player_t* player)
7561 {
7562         MMPLAYER_RETURN_IF_FAIL(player);
7563
7564         if (player->eos_timer) {
7565                 LOGD("cancel eos timer");
7566                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7567                 player->eos_timer = 0;
7568         }
7569
7570         return;
7571 }
7572
7573 static void
7574 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7575 {
7576         MMPLAYER_FENTER();
7577
7578         MMPLAYER_RETURN_IF_FAIL(player);
7579         MMPLAYER_RETURN_IF_FAIL(sink);
7580
7581         player->sink_elements =
7582                 g_list_append(player->sink_elements, sink);
7583
7584         MMPLAYER_FLEAVE();
7585 }
7586
7587 static void
7588 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7589 {
7590         MMPLAYER_FENTER();
7591
7592         MMPLAYER_RETURN_IF_FAIL(player);
7593         MMPLAYER_RETURN_IF_FAIL(sink);
7594
7595         player->sink_elements =
7596                         g_list_remove(player->sink_elements, sink);
7597
7598         MMPLAYER_FLEAVE();
7599 }
7600
7601 void
7602 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7603                         MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7604 {
7605         MMPlayerSignalItem* item = NULL;
7606
7607         MMPLAYER_FENTER();
7608         MMPLAYER_RETURN_IF_FAIL(player);
7609
7610         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7611                 LOGE("invalid signal type [%d]", type);
7612                 return;
7613         }
7614
7615         item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7616         if (!item) {
7617                 LOGE("cannot connect signal [%s]", signal);
7618                 return;
7619         }
7620
7621         item->obj = object;
7622         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7623         player->signals[type] = g_list_append(player->signals[type], item);
7624
7625         MMPLAYER_FLEAVE();
7626         return;
7627 }
7628
7629 /* NOTE : be careful with calling this api. please refer to below glib comment
7630  * glib comment : Note that there is a bug in GObject that makes this function much
7631  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7632  * will no longer be called, but, the signal handler is not currently disconnected.
7633  * If the instance is itself being freed at the same time than this doesn't matter,
7634  * since the signal will automatically be removed, but if instance persists,
7635  * then the signal handler will leak. You should not remove the signal yourself
7636  * because in a future versions of GObject, the handler will automatically be
7637  * disconnected.
7638  *
7639  * It's possible to work around this problem in a way that will continue to work
7640  * with future versions of GObject by checking that the signal handler is still
7641  * connected before disconnected it:
7642  *
7643  *  if (g_signal_handler_is_connected(instance, id))
7644  *    g_signal_handler_disconnect(instance, id);
7645  */
7646 static void
7647 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7648 {
7649         GList* sig_list = NULL;
7650         MMPlayerSignalItem* item = NULL;
7651
7652         MMPLAYER_FENTER();
7653
7654         MMPLAYER_RETURN_IF_FAIL(player);
7655
7656         LOGD("release signals type : %d", type);
7657
7658         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7659                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7660                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7661                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7662                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7663                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7664                 return;
7665         }
7666
7667         sig_list = player->signals[type];
7668
7669         for (; sig_list; sig_list = sig_list->next) {
7670                 item = sig_list->data;
7671
7672                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7673                         if (g_signal_handler_is_connected(item->obj, item->sig))
7674                                 g_signal_handler_disconnect(item->obj, item->sig);
7675                 }
7676
7677                 MMPLAYER_FREEIF(item);
7678         }
7679
7680         g_list_free(player->signals[type]);
7681         player->signals[type] = NULL;
7682
7683         MMPLAYER_FLEAVE();
7684
7685         return;
7686 }
7687
7688 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7689 {
7690         mm_player_t* player = 0;
7691         int prev_display_surface_type = 0;
7692         void *prev_display_overlay = NULL;
7693
7694         MMPLAYER_FENTER();
7695
7696         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7697         MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7698
7699         player = MM_PLAYER_CAST(handle);
7700
7701         /* check video sinkbin is created */
7702         if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7703                 LOGE("Videosink is already created");
7704                 return MM_ERROR_NONE;
7705         }
7706
7707         LOGD("videosink element is not yet ready");
7708
7709         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7710                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7711                 MMPLAYER_FLEAVE();
7712                 return MM_ERROR_INVALID_ARGUMENT;
7713         }
7714
7715         /* load previous attributes */
7716         if (player->attrs) {
7717                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7718                 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7719                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7720                 if (prev_display_surface_type == surface_type) {
7721                         LOGD("incoming display surface type is same as previous one, do nothing..");
7722                         MMPLAYER_FLEAVE();
7723                         return MM_ERROR_NONE;
7724                 }
7725         } else {
7726                 LOGE("failed to load attributes");
7727                 MMPLAYER_FLEAVE();
7728                 return MM_ERROR_PLAYER_INTERNAL;
7729         }
7730
7731         /* videobin is not created yet, so we just set attributes related to display surface */
7732         LOGD("store display attribute for given surface type(%d)", surface_type);
7733         mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7734         mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7735         if (mm_attrs_commit_all(player->attrs)) {
7736                 LOGE("failed to commit attribute");
7737                 MMPLAYER_FLEAVE();
7738                 return MM_ERROR_PLAYER_INTERNAL;
7739         }
7740
7741         MMPLAYER_FLEAVE();
7742         return MM_ERROR_NONE;
7743 }
7744
7745 /* Note : if silent is true, then subtitle would not be displayed. :*/
7746 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7747 {
7748         mm_player_t* player = (mm_player_t*) hplayer;
7749
7750         MMPLAYER_FENTER();
7751
7752         /* check player handle */
7753         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7754
7755         player->set_mode.subtitle_off = silent;
7756
7757         LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7758
7759         MMPLAYER_FLEAVE();
7760
7761         return MM_ERROR_NONE;
7762 }
7763
7764 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7765 {
7766         MMPlayerGstElement* mainbin = NULL;
7767         MMPlayerGstElement* textbin = NULL;
7768         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7769         GstState current_state = GST_STATE_VOID_PENDING;
7770         GstState element_state = GST_STATE_VOID_PENDING;
7771         GstState element_pending_state = GST_STATE_VOID_PENDING;
7772         gint64 time = 0;
7773         GstEvent *event = NULL;
7774         int result = MM_ERROR_NONE;
7775
7776         GstClock *curr_clock = NULL;
7777         GstClockTime base_time, start_time, curr_time;
7778
7779
7780         MMPLAYER_FENTER();
7781
7782         /* check player handle */
7783         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7784                                                                 player->pipeline &&
7785                                                                 player->pipeline->mainbin &&
7786                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7787
7788         mainbin = player->pipeline->mainbin;
7789         textbin = player->pipeline->textbin;
7790
7791         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7792
7793         // sync clock with current pipeline
7794         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7795         curr_time = gst_clock_get_time(curr_clock);
7796
7797         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7798         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7799
7800         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7801                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7802
7803         if (current_state > GST_STATE_READY) {
7804                 // sync state with current pipeline
7805                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7806                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7807                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7808
7809                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7810                 if (GST_STATE_CHANGE_FAILURE == ret) {
7811                         LOGE("fail to state change.\n");
7812                         result = MM_ERROR_PLAYER_INTERNAL;
7813                         goto ERROR;
7814                 }
7815         }
7816
7817         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7818         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7819
7820         if (curr_clock) {
7821                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7822                 gst_object_unref(curr_clock);
7823         }
7824
7825         // seek to current position
7826         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7827                 result = MM_ERROR_PLAYER_INVALID_STATE;
7828                 LOGE("gst_element_query_position failed, invalid state\n");
7829                 goto ERROR;
7830         }
7831
7832         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7833         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);
7834         if (event) {
7835                 __mmplayer_gst_send_event_to_sink(player, event);
7836         } else {
7837                 result = MM_ERROR_PLAYER_INTERNAL;
7838                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7839                 goto ERROR;
7840         }
7841
7842         /* sync state with current pipeline */
7843         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7844         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7845         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7846
7847         return MM_ERROR_NONE;
7848
7849 ERROR:
7850         /* release text pipeline resource */
7851         player->textsink_linked = 0;
7852
7853         /* release signal */
7854         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7855
7856         /* release textbin with it's childs */
7857         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7858         MMPLAYER_FREEIF(player->pipeline->textbin);
7859         player->pipeline->textbin = NULL;
7860
7861         /* release subtitle elem */
7862         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7863         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7864
7865         return result;
7866 }
7867
7868 static int
7869 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7870 {
7871         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7872         GstState current_state = GST_STATE_VOID_PENDING;
7873
7874         MMHandleType attrs = 0;
7875         MMPlayerGstElement* mainbin = NULL;
7876         MMPlayerGstElement* textbin = NULL;
7877
7878         gchar* subtitle_uri = NULL;
7879         int result = MM_ERROR_NONE;
7880         const gchar *charset = NULL;
7881
7882         MMPLAYER_FENTER();
7883
7884         /* check player handle */
7885         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7886                                                                 player->pipeline &&
7887                                                                 player->pipeline->mainbin &&
7888                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7889         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7890
7891         mainbin = player->pipeline->mainbin;
7892         textbin = player->pipeline->textbin;
7893
7894         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7895         if (current_state < GST_STATE_READY) {
7896                 result = MM_ERROR_PLAYER_INVALID_STATE;
7897                 LOGE("Pipeline is not in proper state\n");
7898                 goto EXIT;
7899         }
7900
7901         attrs = MMPLAYER_GET_ATTRS(player);
7902         if (!attrs) {
7903                 LOGE("cannot get content attribute\n");
7904                 result = MM_ERROR_PLAYER_INTERNAL;
7905                 goto EXIT;
7906         }
7907
7908         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7909         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7910                 LOGE("subtitle uri is not proper filepath\n");
7911                 result = MM_ERROR_PLAYER_INVALID_URI;
7912                 goto EXIT;
7913         }
7914
7915         if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7916                 LOGE("failed to get storage info of subtitle path");
7917                 result = MM_ERROR_PLAYER_INVALID_URI;
7918                 goto EXIT;
7919         }
7920
7921         LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7922         LOGD("new subtitle file path is [%s]\n", filepath);
7923
7924         if (!strcmp(filepath, subtitle_uri)) {
7925                 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7926                 goto EXIT;
7927         } else {
7928                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7929                 if (mm_attrs_commit_all(player->attrs)) {
7930                         LOGE("failed to commit.\n");
7931                         goto EXIT;
7932                 }
7933         }
7934
7935         //gst_pad_set_blocked_async(src-srcpad, TRUE)
7936         MMPLAYER_SUBTITLE_INFO_LOCK(player);
7937         player->subtitle_language_list = NULL;
7938         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7939
7940         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7941         if (ret != GST_STATE_CHANGE_SUCCESS) {
7942                 LOGE("failed to change state of textbin to READY");
7943                 result = MM_ERROR_PLAYER_INTERNAL;
7944                 goto EXIT;
7945         }
7946
7947         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7948         if (ret != GST_STATE_CHANGE_SUCCESS) {
7949                 LOGE("failed to change state of subparse to READY");
7950                 result = MM_ERROR_PLAYER_INTERNAL;
7951                 goto EXIT;
7952         }
7953
7954         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7955         if (ret != GST_STATE_CHANGE_SUCCESS) {
7956                 LOGE("failed to change state of filesrc to READY");
7957                 result = MM_ERROR_PLAYER_INTERNAL;
7958                 goto EXIT;
7959         }
7960
7961         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7962
7963         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7964
7965         charset = util_get_charset(filepath);
7966         if (charset) {
7967                 LOGD("detected charset is %s\n", charset);
7968                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7969         }
7970
7971         result = _mmplayer_sync_subtitle_pipeline(player);
7972
7973 EXIT:
7974         MMPLAYER_FLEAVE();
7975         return result;
7976 }
7977
7978 /* API to switch between external subtitles */
7979 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7980 {
7981         int result = MM_ERROR_NONE;
7982         mm_player_t* player = (mm_player_t*)hplayer;
7983         char *path = NULL;
7984
7985         MMPLAYER_FENTER();
7986
7987         /* check player handle */
7988         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7989
7990         /* filepath can be null in idle state */
7991         if (filepath) {
7992                 /* check file path */
7993                 if ((path = strstr(filepath, "file://")))
7994                         result = util_exist_file_path(path + 7);
7995                 else
7996                         result = util_exist_file_path(filepath);
7997
7998                 if (result != MM_ERROR_NONE) {
7999                         LOGE("invalid subtitle path 0x%X", result);
8000                         return result; /* file not found or permission denied */
8001                 }
8002         }
8003
8004         if (!player->pipeline) {
8005                 /* IDLE state */
8006                 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8007                 if (mm_attrs_commit_all(player->attrs)) {
8008                         LOGE("failed to commit");       /* subtitle path will not be created */
8009                         return MM_ERROR_PLAYER_INTERNAL;
8010                 }
8011         } else {
8012                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8013                 /* check filepath */
8014                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8015
8016                 if (!__mmplayer_check_subtitle(player)) {
8017                         mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8018                         if (mm_attrs_commit_all(player->attrs)) {
8019                                 LOGE("failed to commit");
8020                                 return MM_ERROR_PLAYER_INTERNAL;
8021                         }
8022
8023                         if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8024                                 LOGE("fail to create text pipeline");
8025                                 return MM_ERROR_PLAYER_INTERNAL;
8026                         }
8027
8028                         result = _mmplayer_sync_subtitle_pipeline(player);
8029                 } else {
8030                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8031                 }
8032
8033                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8034                 player->is_external_subtitle_added_now = TRUE;
8035
8036                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8037                 if (!player->subtitle_language_list) {
8038                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8039                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8040                                 LOGW("subtitle language list is not updated yet");
8041                 }
8042                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8043         }
8044
8045         MMPLAYER_FLEAVE();
8046         return result;
8047 }
8048
8049 static int
8050 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8051 {
8052         int result = MM_ERROR_NONE;
8053         gchar* change_pad_name = NULL;
8054         GstPad* sinkpad = NULL;
8055         MMPlayerGstElement* mainbin = NULL;
8056         enum MainElementID elem_idx = MMPLAYER_M_NUM;
8057         GstCaps* caps = NULL;
8058         gint total_track_num = 0;
8059
8060         MMPLAYER_FENTER();
8061
8062         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8063                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8064
8065         LOGD("Change Track(%d) to %d\n", type, index);
8066
8067         mainbin = player->pipeline->mainbin;
8068
8069         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8070                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8071         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8072                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8073         } else {
8074                 /* Changing Video Track is not supported. */
8075                 LOGE("Track Type Error\n");
8076                 goto EXIT;
8077         }
8078
8079         if (mainbin[elem_idx].gst == NULL) {
8080                 result = MM_ERROR_PLAYER_NO_OP;
8081                 LOGD("Req track doesn't exist\n");
8082                 goto EXIT;
8083         }
8084
8085         total_track_num = player->selector[type].total_track_num;
8086         if (total_track_num <= 0) {
8087                 result = MM_ERROR_PLAYER_NO_OP;
8088                 LOGD("Language list is not available \n");
8089                 goto EXIT;
8090         }
8091
8092         if ((index < 0) || (index >= total_track_num)) {
8093                 result = MM_ERROR_INVALID_ARGUMENT;
8094                 LOGD("Not a proper index : %d \n", index);
8095                 goto EXIT;
8096         }
8097
8098         /*To get the new pad from the selector*/
8099         change_pad_name = g_strdup_printf("sink_%u", index);
8100         if (change_pad_name == NULL) {
8101                 result = MM_ERROR_PLAYER_INTERNAL;
8102                 LOGD("Pad does not exists\n");
8103                 goto EXIT;
8104         }
8105
8106         LOGD("new active pad name: %s\n", change_pad_name);
8107
8108         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8109         if (sinkpad == NULL) {
8110                 LOGD("sinkpad is NULL");
8111                 result = MM_ERROR_PLAYER_INTERNAL;
8112                 goto EXIT;
8113         }
8114
8115         LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8116         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8117
8118         caps = gst_pad_get_current_caps(sinkpad);
8119         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8120
8121         if (sinkpad)
8122                 gst_object_unref(sinkpad);
8123
8124         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8125                 __mmplayer_set_audio_attrs(player, caps);
8126
8127 EXIT:
8128
8129         MMPLAYER_FREEIF(change_pad_name);
8130         return result;
8131 }
8132
8133 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8134 {
8135         int result = MM_ERROR_NONE;
8136         mm_player_t* player = NULL;
8137         MMPlayerGstElement* mainbin = NULL;
8138
8139         gint current_active_index = 0;
8140
8141         GstState current_state = GST_STATE_VOID_PENDING;
8142         GstEvent* event = NULL;
8143         gint64 time = 0;
8144
8145         MMPLAYER_FENTER();
8146
8147         player = (mm_player_t*)hplayer;
8148         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8149
8150         if (!player->pipeline) {
8151                 LOGE("Track %d pre setting -> %d\n", type, index);
8152
8153                 player->selector[type].active_pad_index = index;
8154                 goto EXIT;
8155         }
8156
8157         mainbin = player->pipeline->mainbin;
8158
8159         current_active_index = player->selector[type].active_pad_index;
8160
8161         /*If index is same as running index no need to change the pad*/
8162         if (current_active_index == index)
8163                 goto EXIT;
8164
8165         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8166                 result = MM_ERROR_PLAYER_INVALID_STATE;
8167                 goto EXIT;
8168         }
8169
8170         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8171         if (current_state < GST_STATE_PAUSED) {
8172                 result = MM_ERROR_PLAYER_INVALID_STATE;
8173                 LOGW("Pipeline not in porper state\n");
8174                 goto EXIT;
8175         }
8176
8177         result = __mmplayer_change_selector_pad(player, type, index);
8178         if (result != MM_ERROR_NONE) {
8179                 LOGE("change selector pad error\n");
8180                 goto EXIT;
8181         }
8182
8183         player->selector[type].active_pad_index = index;
8184
8185         if (current_state == GST_STATE_PLAYING) {
8186                 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);
8187                 if (event) {
8188                         __mmplayer_gst_send_event_to_sink(player, event);
8189                 } else {
8190                         result = MM_ERROR_PLAYER_INTERNAL;
8191                         goto EXIT;
8192                 }
8193         }
8194
8195 EXIT:
8196         return result;
8197 }
8198
8199 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8200 {
8201         mm_player_t* player = (mm_player_t*) hplayer;
8202
8203         MMPLAYER_FENTER();
8204
8205         /* check player handle */
8206         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8207
8208         *silent = player->set_mode.subtitle_off;
8209
8210         LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8211
8212         MMPLAYER_FLEAVE();
8213
8214         return MM_ERROR_NONE;
8215 }
8216
8217 static gboolean
8218 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8219 {
8220         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8221         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8222
8223         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8224         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8225
8226         int idx = 0;
8227
8228         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8229                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8230                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8231                         mm_player_dump_t *dump_s;
8232                         dump_s = g_malloc(sizeof(mm_player_dump_t));
8233
8234                         if (dump_s == NULL) {
8235                                 LOGE("malloc fail");
8236                                 return FALSE;
8237                         }
8238
8239                         dump_s->dump_element_file = NULL;
8240                         dump_s->dump_pad = NULL;
8241                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8242
8243                         if (dump_s->dump_pad) {
8244                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8245                                 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]);
8246                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8247                                 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);
8248                                 /* add list for removed buffer probe and close FILE */
8249                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8250                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8251                                 return TRUE;
8252                         } else {
8253                                 g_free(dump_s);
8254                                 dump_s = NULL;
8255                                 LOGE("failed to get %s sink pad added", factory_name);
8256                         }
8257                 }
8258         }
8259         return FALSE;
8260 }
8261
8262 static GstPadProbeReturn
8263 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8264 {
8265         FILE *dump_data = (FILE *) u_data;
8266 //      int written = 0;
8267         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8268         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8269
8270         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8271
8272         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8273
8274 //      LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8275
8276         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8277
8278         return GST_PAD_PROBE_OK;
8279 }
8280
8281 static void
8282 __mmplayer_release_dump_list(GList *dump_list)
8283 {
8284         if (dump_list) {
8285                 GList *d_list = dump_list;
8286                 for (; d_list; d_list = g_list_next(d_list)) {
8287                         mm_player_dump_t *dump_s = d_list->data;
8288                         if (dump_s->dump_pad) {
8289                                 if (dump_s->probe_handle_id)
8290                                         gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8291                         }
8292                         if (dump_s->dump_element_file) {
8293                                 fclose(dump_s->dump_element_file);
8294                                 dump_s->dump_element_file = NULL;
8295                         }
8296                         MMPLAYER_FREEIF(dump_s);
8297                 }
8298                 g_list_free(dump_list);
8299                 dump_list = NULL;
8300         }
8301 }
8302
8303 int
8304 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8305 {
8306         mm_player_t* player = (mm_player_t*) hplayer;
8307
8308         MMPLAYER_FENTER();
8309
8310         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8311         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8312
8313         *exist = player->has_closed_caption;
8314
8315         MMPLAYER_FLEAVE();
8316
8317         return MM_ERROR_NONE;
8318 }
8319
8320 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8321 {
8322         MMPLAYER_FENTER();
8323         if (buffer) {
8324                 // LOGD("unref internal gst buffer %p", buffer);
8325                 gst_buffer_unref((GstBuffer *)buffer);
8326                 buffer = NULL;
8327         }
8328         MMPLAYER_FLEAVE();
8329 }
8330
8331 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8332 {
8333         mm_player_t* player = (mm_player_t*) hplayer;
8334
8335         MMPLAYER_FENTER();
8336
8337         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8338         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8339
8340         if (MMPLAYER_IS_HTTP_PD(player))
8341                 /* consider the timeout both download pipeline and playback pipeline */
8342                 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8343         else if (MMPLAYER_IS_STREAMING(player))
8344                 *timeout = player->ini.live_state_change_timeout;
8345         else
8346                 *timeout = player->ini.localplayback_state_change_timeout;
8347
8348         LOGD("timeout = %d\n", *timeout);
8349
8350         MMPLAYER_FLEAVE();
8351         return MM_ERROR_NONE;
8352 }
8353
8354 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8355 {
8356         mm_player_t* player = (mm_player_t*) hplayer;
8357
8358         MMPLAYER_FENTER();
8359
8360         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8361         MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8362
8363         *num = player->video_num_buffers;
8364         *extra_num = player->video_extra_num_buffers;
8365
8366         LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8367
8368         MMPLAYER_FLEAVE();
8369         return MM_ERROR_NONE;
8370 }
8371
8372 static void
8373 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8374 {
8375         int i = 0;
8376         MMPLAYER_FENTER();
8377         MMPLAYER_RETURN_IF_FAIL(player);
8378
8379         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8380
8381                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8382                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8383                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8384                         player->storage_info[i].id = -1;
8385                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8386
8387                         if (path_type != MMPLAYER_PATH_MAX)
8388                                 break;
8389                 }
8390         }
8391
8392         MMPLAYER_FLEAVE();
8393 }
8394
8395 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8396 {
8397         int ret = MM_ERROR_NONE;
8398         mm_player_t* player = (mm_player_t*)hplayer;
8399         MMMessageParamType msg_param = {0, };
8400
8401         MMPLAYER_FENTER();
8402         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8403
8404         LOGW("state changed storage %d:%d", id, state);
8405
8406         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8407                 return MM_ERROR_NONE;
8408
8409         /* FIXME: text path should be handled seperately. */
8410         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8411                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8412                 LOGW("external storage is removed");
8413
8414                 if (player->msg_posted == FALSE) {
8415                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8416                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8417                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8418                         player->msg_posted = TRUE;
8419                 }
8420
8421                 /* unrealize the player */
8422                 ret = _mmplayer_unrealize(hplayer);
8423                 if (ret != MM_ERROR_NONE)
8424                         LOGE("failed to unrealize");
8425         }
8426
8427         MMPLAYER_FLEAVE();
8428         return ret;
8429 }
8430
8431 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8432 {
8433         int ret = MM_ERROR_NONE;
8434         mm_player_t* player = (mm_player_t*) hplayer;
8435         int idx = 0, total = 0;
8436         gchar *result = NULL, *tmp = NULL;
8437
8438         MMPLAYER_FENTER();
8439         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8440         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8441
8442         total = *num = g_list_length(player->adaptive_info.var_list);
8443         if (total <= 0) {
8444                 LOGW("There is no stream variant info.");
8445                 return ret;
8446         }
8447
8448         result = g_strdup("");
8449         for (idx = 0 ; idx < total ; idx++) {
8450                 VariantData *v_data = NULL;
8451                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8452
8453                 if (v_data) {
8454                         gchar data[64] = {0};
8455                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8456
8457                         tmp = g_strconcat(result, data, NULL);
8458                         g_free(result);
8459                         result = tmp;
8460                 } else {
8461                         LOGW("There is no variant data in %d", idx);
8462                         (*num)--;
8463                 }
8464         }
8465
8466         *var_info = (char *)result;
8467
8468         LOGD("variant info %d:%s", *num, *var_info);
8469         MMPLAYER_FLEAVE();
8470         return ret;
8471 }
8472
8473 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8474 {
8475         int ret = MM_ERROR_NONE;
8476         mm_player_t* player = (mm_player_t*) hplayer;
8477
8478         MMPLAYER_FENTER();
8479         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8480
8481         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8482
8483         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8484         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8485         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8486
8487         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8488                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8489                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8490                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8491
8492                 /* FIXME: seek to current position for applying new variant limitation */
8493         }
8494
8495         MMPLAYER_FLEAVE();
8496         return ret;
8497
8498 }
8499
8500 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8501 {
8502         int ret = MM_ERROR_NONE;
8503         mm_player_t* player = (mm_player_t*) hplayer;
8504
8505         MMPLAYER_FENTER();
8506         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8507         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8508
8509         *bandwidth = player->adaptive_info.limit.bandwidth;
8510         *width = player->adaptive_info.limit.width;
8511         *height = player->adaptive_info.limit.height;
8512
8513         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8514
8515         MMPLAYER_FLEAVE();
8516         return ret;
8517 }
8518
8519 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8520 {
8521         int ret = MM_ERROR_NONE;
8522         mm_player_t* player = (mm_player_t*) hplayer;
8523
8524         MMPLAYER_FENTER();
8525         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526
8527         if (MMPLAYER_CURRENT_STATE(player) !=  MM_PLAYER_STATE_NULL)
8528                 LOGW("buffer_ms will not be applied.");
8529
8530
8531         LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8532
8533         if (player->streamer == NULL) {
8534                 player->streamer = __mm_player_streaming_create();
8535                 __mm_player_streaming_initialize(player->streamer);
8536         }
8537
8538         if (buffer_ms >= 0)
8539                 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8540
8541         if (rebuffer_ms >= 0)
8542                 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8543
8544         MMPLAYER_FLEAVE();
8545         return ret;
8546
8547 }
8548
8549 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8550 {
8551         int ret = MM_ERROR_NONE;
8552         mm_player_t* player = (mm_player_t*) hplayer;
8553
8554         MMPLAYER_FENTER();
8555         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556         MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8557
8558         if (player->streamer == NULL) {
8559                 player->streamer = __mm_player_streaming_create();
8560                 __mm_player_streaming_initialize(player->streamer);
8561         }
8562
8563         *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8564         *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8565
8566         LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8567
8568         MMPLAYER_FLEAVE();
8569         return ret;
8570 }
8571
8572 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8573 {
8574 #define IDX_FIRST_SW_CODEC 0
8575         mm_player_t* player = (mm_player_t*) hplayer;
8576         const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8577         MMHandleType attrs = 0;
8578
8579         MMPLAYER_FENTER();
8580         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8581
8582         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8583                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8584                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8585
8586         switch (stream_type) {
8587         case MM_PLAYER_STREAM_TYPE_AUDIO:
8588         /* to support audio codec selection, codec info have to be added in ini file as below.
8589            audio codec element hw = xxxx
8590            audio codec element sw = avdec */
8591                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8592                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8593                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8594                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8595                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8596                         return MM_ERROR_PLAYER_NO_OP;
8597                 }
8598         break;
8599         case MM_PLAYER_STREAM_TYPE_VIDEO:
8600         /* to support video codec selection, codec info have to be added in ini file as below.
8601            video codec element hw = omx
8602            video codec element sw = avdec */
8603                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8604                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8605                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8606                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8607                         LOGE("There is no video codec info for codec_type %d", codec_type);
8608                         return MM_ERROR_PLAYER_NO_OP;
8609                 }
8610         break;
8611         default:
8612                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8613                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8614         break;
8615         }
8616
8617         LOGD("update %s codec_type to %d", attr_name, codec_type);
8618
8619         attrs = MMPLAYER_GET_ATTRS(player);
8620         mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8621
8622         if (mm_attrs_commit_all(player->attrs)) {
8623                 LOGE("failed to commit codec_type attributes");
8624                 return MM_ERROR_PLAYER_INTERNAL;
8625         }
8626
8627         MMPLAYER_FLEAVE();
8628         return MM_ERROR_NONE;
8629 }
8630
8631 int
8632 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8633 {
8634         mm_player_t* player = (mm_player_t*) hplayer;
8635         GstElement* rg_vol_element = NULL;
8636
8637         MMPLAYER_FENTER();
8638
8639         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8640
8641         player->sound.rg_enable = enabled;
8642
8643         /* just hold rgvolume enable value if pipeline is not ready */
8644         if (!player->pipeline || !player->pipeline->audiobin) {
8645                 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8646                 return MM_ERROR_NONE;
8647         }
8648
8649         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8650
8651         if (!rg_vol_element) {
8652                 LOGD("rgvolume element is not created");
8653                 return MM_ERROR_PLAYER_INTERNAL;
8654         }
8655
8656         if (enabled)
8657                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8658         else
8659                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8660
8661         MMPLAYER_FLEAVE();
8662
8663         return MM_ERROR_NONE;
8664 }
8665
8666 int
8667 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8668 {
8669         mm_player_t* player = (mm_player_t*) hplayer;
8670         GstElement* rg_vol_element = NULL;
8671         gboolean enable = FALSE;
8672
8673         MMPLAYER_FENTER();
8674
8675         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8676         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8677
8678         /* just hold enable_rg value if pipeline is not ready */
8679         if (!player->pipeline || !player->pipeline->audiobin) {
8680                 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8681                 *enabled = player->sound.rg_enable;
8682                 return MM_ERROR_NONE;
8683         }
8684
8685         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8686
8687         if (!rg_vol_element) {
8688                 LOGD("rgvolume element is not created");
8689                 return MM_ERROR_PLAYER_INTERNAL;
8690         }
8691
8692         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8693         *enabled = enable;
8694
8695         MMPLAYER_FLEAVE();
8696
8697         return MM_ERROR_NONE;
8698 }
8699
8700 int
8701 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8702 {
8703         mm_player_t* player = (mm_player_t*) hplayer;
8704         MMHandleType attrs = 0;
8705         void *handle = NULL;
8706         int ret = MM_ERROR_NONE;
8707
8708         MMPLAYER_FENTER();
8709
8710         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8711
8712         attrs = MMPLAYER_GET_ATTRS(player);
8713         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8714
8715         mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8716         if (!handle) {
8717                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8718                 return MM_ERROR_PLAYER_INTERNAL;
8719         }
8720
8721         player->video_roi.scale_x = scale_x;
8722         player->video_roi.scale_y = scale_y;
8723         player->video_roi.scale_width = scale_width;
8724         player->video_roi.scale_height = scale_height;
8725
8726         /* check video sinkbin is created */
8727         if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8728                 return MM_ERROR_NONE;
8729
8730         if (!gst_video_overlay_set_video_roi_area(
8731                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8732                 scale_x, scale_y, scale_width, scale_height))
8733                 ret = MM_ERROR_PLAYER_INTERNAL;
8734         else
8735                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8736                         scale_x, scale_y, scale_width, scale_height);
8737
8738         MMPLAYER_FLEAVE();
8739
8740         return ret;
8741 }
8742
8743 int
8744 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8745 {
8746         mm_player_t* player = (mm_player_t*) hplayer;
8747         int ret = MM_ERROR_NONE;
8748
8749         MMPLAYER_FENTER();
8750
8751         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8752         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8753
8754         *scale_x = player->video_roi.scale_x;
8755         *scale_y = player->video_roi.scale_y;
8756         *scale_width = player->video_roi.scale_width;
8757         *scale_height = player->video_roi.scale_height;
8758
8759         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8760                 *scale_x, *scale_y, *scale_width, *scale_height);
8761
8762         return ret;
8763 }
8764
8765 static gboolean
8766 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8767 {
8768         gboolean ret = FALSE;
8769         gint64 dur_nsec = 0;
8770         LOGD("try to update duration");
8771
8772         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8773                 player->duration = dur_nsec;
8774                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8775                 ret = TRUE;
8776         }
8777
8778         if (player->duration < 0) {
8779                 LOGW("duration is Non-Initialized !!!");
8780                 player->duration = 0;
8781         }
8782
8783         /* update streaming service type */
8784         player->streaming_type =  __mmplayer_get_stream_service_type(player);
8785
8786         /* check duration is OK */
8787         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8788                 /* FIXIT : find another way to get duration here. */
8789                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8790         }
8791
8792         return ret;
8793 }
8794
8795 static gboolean
8796 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8797 {
8798         /* update audio params
8799         NOTE : We need original audio params and it can be only obtained from src pad of audio
8800         decoder. Below code only valid when we are not using 'resampler' just before
8801         'audioconverter'. */
8802         GstCaps *caps_a = NULL;
8803         GstPad* pad = NULL;
8804         gint samplerate = 0, channels = 0;
8805         GstStructure* p = NULL;
8806
8807         LOGD("try to update audio attrs");
8808
8809         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8810         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8811
8812         pad = gst_element_get_static_pad(
8813                         player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8814
8815         if (!pad) {
8816                 LOGW("failed to get pad from audiosink");
8817                 return FALSE;
8818         }
8819
8820         caps_a = gst_pad_get_current_caps(pad);
8821
8822         if (!caps_a) {
8823                 LOGW("not ready to get audio caps");
8824                 gst_object_unref(pad);
8825                 return FALSE;
8826         }
8827
8828         p = gst_caps_get_structure(caps_a, 0);
8829
8830         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8831
8832         gst_structure_get_int(p, "rate", &samplerate);
8833         mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8834
8835         gst_structure_get_int(p, "channels", &channels);
8836         mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8837
8838         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8839
8840         gst_caps_unref(caps_a);
8841         gst_object_unref(pad);
8842
8843         return TRUE;
8844 }
8845
8846 static gboolean
8847 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8848 {
8849         LOGD("try to update video attrs");
8850
8851         GstCaps *caps_v = NULL;
8852         GstPad* pad = NULL;
8853         gint tmpNu, tmpDe;
8854         gint width, height;
8855         GstStructure* p = NULL;
8856
8857         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8858         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8859
8860         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8861         if (!pad) {
8862                 LOGD("no videosink sink pad");
8863                 return FALSE;
8864         }
8865
8866         caps_v = gst_pad_get_current_caps(pad);
8867         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8868         if (!caps_v && player->v_stream_caps) {
8869                 caps_v = player->v_stream_caps;
8870                 gst_caps_ref(caps_v);
8871         }
8872
8873         if (!caps_v) {
8874                 LOGD("no negitiated caps from videosink");
8875                 gst_object_unref(pad);
8876                 return FALSE;
8877         }
8878
8879         p = gst_caps_get_structure(caps_v, 0);
8880         gst_structure_get_int(p, "width", &width);
8881         mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8882
8883         gst_structure_get_int(p, "height", &height);
8884         mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8885
8886         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8887
8888         SECURE_LOGD("width : %d     height : %d", width, height);
8889
8890         gst_caps_unref(caps_v);
8891         gst_object_unref(pad);
8892
8893         if (tmpDe > 0) {
8894                 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8895                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8896         }
8897
8898         return TRUE;
8899 }
8900
8901 static gboolean
8902 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8903 {
8904         gboolean ret = FALSE;
8905         guint64 data_size = 0;
8906         gchar *path = NULL;
8907         struct stat sb;
8908
8909         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8910         if (!player->duration)
8911                 return FALSE;
8912
8913         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8914                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8915                 if (stat(path, &sb) == 0)
8916                         data_size = (guint64)sb.st_size;
8917
8918         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8919                 data_size = player->http_content_size;
8920         }
8921
8922         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8923
8924         if (data_size) {
8925                 guint64 bitrate = 0;
8926                 guint64 msec_dur = 0;
8927
8928                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8929                 if (msec_dur > 0) {
8930                         bitrate = data_size * 8 * 1000 / msec_dur;
8931                         SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
8932                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8933
8934                         ret = TRUE;
8935                 } else {
8936                         LOGD("player duration is less than 0");
8937                 }
8938         }
8939
8940         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8941                 if (player->total_bitrate) {
8942                         mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8943                         ret = TRUE;
8944                 }
8945         }
8946
8947         return ret;
8948 }
8949 static void
8950 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8951 {
8952         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8953         data->uri_type = uri_type;
8954 }
8955 static int
8956 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8957 {
8958         int ret = MM_ERROR_PLAYER_INVALID_URI;
8959         int mem_size = 0;
8960         char *buffer = NULL;
8961         char *seperator = strchr(path, ',');
8962         char ext[100] = {0,}, size[100] = {0,};
8963
8964         if (seperator) {
8965                 if ((buffer = strstr(path, "ext="))) {
8966                         buffer += strlen("ext=");
8967
8968                         if (strlen(buffer)) {
8969                                 strncpy(ext, buffer, 99);
8970
8971                                 if ((seperator = strchr(ext, ','))
8972                                         || (seperator = strchr(ext, ' '))
8973                                         || (seperator = strchr(ext, '\0'))) {
8974                                         seperator[0] = '\0';
8975                                 }
8976                         }
8977                 }
8978
8979                 if ((buffer = strstr(path, "size="))) {
8980                         buffer += strlen("size=");
8981
8982                         if (strlen(buffer) > 0) {
8983                                 strncpy(size, buffer, 99);
8984
8985                                 if ((seperator = strchr(size, ','))
8986                                         || (seperator = strchr(size, ' '))
8987                                         || (seperator = strchr(size, '\0'))) {
8988                                         seperator[0] = '\0';
8989                                 }
8990
8991                                 mem_size = atoi(size);
8992                         }
8993                 }
8994         }
8995
8996         LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8997
8998         if (mem_size && param) {
8999                 if (data->input_mem.buf)
9000                         free(data->input_mem.buf);
9001                 data->input_mem.buf = malloc(mem_size);
9002
9003                 if (data->input_mem.buf) {
9004                         memcpy(data->input_mem.buf, param, mem_size);
9005                         data->input_mem.len = mem_size;
9006                         ret = MM_ERROR_NONE;
9007                 } else {
9008                         LOGE("failed to alloc mem %d", mem_size);
9009                         ret = MM_ERROR_PLAYER_INTERNAL;
9010                 }
9011
9012                 data->input_mem.offset = 0;
9013                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9014         }
9015
9016         return ret;
9017 }
9018
9019 static int
9020 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9021 {
9022         gchar *location = NULL;
9023         GError *err = NULL;
9024         char *path = NULL;
9025         int ret = MM_ERROR_NONE;
9026
9027         if ((path = strstr(uri, "file://"))) {
9028                 location = g_filename_from_uri(uri, NULL, &err);
9029                 if (!location || (err != NULL)) {
9030                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9031                                 (err != NULL) ? err->message : "unknown error");
9032                         if (err)
9033                                 g_error_free(err);
9034                         if (location)
9035                                 g_free(location);
9036
9037                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9038                         return MM_ERROR_PLAYER_INVALID_URI;
9039                 }
9040                 LOGD("path from uri: %s", location);
9041         }
9042
9043         path = (location != NULL) ? (location) : ((char *)uri);
9044
9045
9046         ret = util_exist_file_path(path);
9047
9048         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9049         if (ret == MM_ERROR_NONE) {
9050                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9051                 if (util_is_sdp_file(path)) {
9052                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9053                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9054                 } else {
9055                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9056                 }
9057         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9058                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9059         } else {
9060                 LOGE("invalid uri, could not play..\n");
9061                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9062         }
9063
9064         if (location)
9065                 g_free(location);
9066
9067         return ret;
9068 }
9069
9070 static MMPlayerVideoStreamDataType*
9071 __mmplayer_create_stream_from_pad(GstPad *pad)
9072 {
9073         GstCaps *caps = NULL;
9074         GstStructure *structure = NULL;
9075         unsigned int fourcc = 0;
9076         const gchar *string_format = NULL;
9077         MMPlayerVideoStreamDataType *stream = NULL;
9078         gint width, height;
9079         MMPixelFormatType format;
9080
9081         caps = gst_pad_get_current_caps(pad);
9082         if (!caps) {
9083                 LOGE("Caps is NULL.");
9084                 return NULL;
9085         }
9086
9087         /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9088         structure = gst_caps_get_structure(caps, 0);
9089         gst_structure_get_int(structure, "width", &width);
9090         gst_structure_get_int(structure, "height", &height);
9091         string_format = gst_structure_get_string(structure, "format");
9092         if (string_format)
9093                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9094         format = util_get_pixtype(fourcc);
9095         gst_caps_unref(caps);
9096
9097         /* moved here */
9098         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9099                 LOGE("Wrong condition!!");
9100                 return NULL;
9101         }
9102
9103         stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9104         if (!stream) {
9105                 LOGE("failed to alloc mem for video data");
9106                 return NULL;
9107         }
9108
9109         stream->width = width;
9110         stream->height = height;
9111         stream->format = format;
9112
9113         return stream;
9114 }
9115
9116 static void
9117 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9118 {
9119         unsigned int pitch = 0;
9120         int index = 0;
9121         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9122
9123         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9124                 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9125                 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9126                 stream->stride[index] = pitch;
9127                 stream->elevation[index] = stream->height;
9128         }
9129 }
9130
9131 static gboolean
9132 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9133 {
9134         if (stream->format == MM_PIXEL_FORMAT_I420) {
9135                 int ret = TBM_SURFACE_ERROR_NONE;
9136                 tbm_surface_h surface;
9137                 tbm_surface_info_s info;
9138
9139                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9140
9141                 ret = tbm_surface_get_info(surface, &info);
9142                 if (ret != TBM_SURFACE_ERROR_NONE) {
9143                         tbm_surface_destroy(surface);
9144                         return FALSE;
9145                 }
9146
9147                 tbm_surface_destroy(surface);
9148                 stream->stride[0] = info.planes[0].stride;
9149                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9150                 stream->stride[1] = info.planes[1].stride;
9151                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9152                 stream->stride[2] = info.planes[2].stride;
9153                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9154                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9155         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9156                 stream->stride[0] = stream->width * 4;
9157                 stream->elevation[0] = stream->height;
9158                 stream->bo_size = stream->stride[0] * stream->height;
9159         } else {
9160                 LOGE("Not support format %d", stream->format);
9161                 return FALSE;
9162         }
9163
9164         return TRUE;
9165 }
9166
9167 static gboolean
9168 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9169 {
9170         tbm_bo_handle thandle;
9171         gboolean is_mapped;
9172         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9173         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9174         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9175         int i = 0;
9176         int j = 0;
9177         int k = 0;
9178         unsigned char *src = NULL;
9179         unsigned char *dest = NULL;
9180         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9181
9182         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9183         if (!is_mapped) {
9184                 LOGE("fail to gst_memory_map");
9185                 return FALSE;
9186         }
9187
9188         if (!mapinfo.data) {
9189                 LOGE("data pointer is wrong");
9190                 goto ERROR;
9191         }
9192
9193         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9194         if (!stream->bo[0]) {
9195                 LOGE("Fail to tbm_bo_alloc!!");
9196                 goto ERROR;
9197         }
9198
9199         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9200         if (!thandle.ptr) {
9201                 LOGE("thandle pointer is wrong");
9202                 goto ERROR;
9203         }
9204
9205         if (stream->format == MM_PIXEL_FORMAT_I420) {
9206                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9207                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9208                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9209                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9210
9211                 dest_offset[0] = 0;
9212                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9213                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9214
9215                 for (i = 0; i < 3; i++) {
9216                         src = mapinfo.data + src_offset[i];
9217                         dest = thandle.ptr + dest_offset[i];
9218
9219                         if (i > 0)
9220                                 k = 1;
9221
9222                         for (j = 0; j < stream->height >> k; j++) {
9223                                 memcpy(dest, src, stream->width>>k);
9224                                 src += src_stride[i];
9225                                 dest += stream->stride[i];
9226                         }
9227                 }
9228         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9229                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9230         } else {
9231                 LOGE("Not support format %d", stream->format);
9232                 goto ERROR;
9233         }
9234
9235         tbm_bo_unmap(stream->bo[0]);
9236         gst_memory_unmap(mem, &mapinfo);
9237
9238         return TRUE;
9239
9240 ERROR:
9241         if (stream->bo[0])
9242                 tbm_bo_unmap(stream->bo[0]);
9243
9244         if (is_mapped)
9245                 gst_memory_unmap(mem, &mapinfo);
9246
9247         return FALSE;
9248 }
9249
9250 static void
9251 __mmplayer_set_pause_state(mm_player_t *player)
9252 {
9253         if (player->sent_bos)
9254                 return;
9255
9256         /* rtsp case, get content attrs by GstMessage */
9257         if (MMPLAYER_IS_RTSP_STREAMING(player))
9258                 return;
9259
9260         /* it's first time to update all content attrs. */
9261         __mmplayer_update_content_attrs(player, ATTR_ALL);
9262 }
9263
9264 static void
9265 __mmplayer_set_playing_state(mm_player_t *player)
9266 {
9267         gchar *audio_codec = NULL;
9268
9269         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9270                 /* initialize because auto resume is done well. */
9271                 player->resumed_by_rewind = FALSE;
9272                 player->playback_rate = 1.0;
9273         }
9274
9275         if (player->sent_bos)
9276                 return;
9277
9278         /* try to get content metadata */
9279
9280         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9281          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9282          * legacy mmfw-player api
9283          */
9284         __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9285
9286         if ((player->cmd == MMPLAYER_COMMAND_START)
9287                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9288                 __mmplayer_handle_missed_plugin(player);
9289         }
9290
9291         /* check audio codec field is set or not
9292          * we can get it from typefinder or codec's caps.
9293          */
9294         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9295
9296         /* The codec format can't be sent for audio only case like amr, mid etc.
9297          * Because, parser don't make related TAG.
9298          * So, if it's not set yet, fill it with found data.
9299          */
9300         if (!audio_codec) {
9301                 if (g_strrstr(player->type, "audio/midi"))
9302                         audio_codec = "MIDI";
9303                 else if (g_strrstr(player->type, "audio/x-amr"))
9304                         audio_codec = "AMR";
9305                 else if (g_strrstr(player->type, "audio/mpeg")
9306                                 && !g_strrstr(player->type, "mpegversion= (int)1"))
9307                         audio_codec = "AAC";
9308                 else
9309                         audio_codec = "unknown";
9310
9311                 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9312
9313                 if (mm_attrs_commit_all(player->attrs))
9314                         LOGE("failed to update attributes\n");
9315
9316                 LOGD("set audio codec type with caps\n");
9317         }
9318
9319         return;
9320 }