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