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