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