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