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