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