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