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