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