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