[0.6.202] remove unused pcm info
[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                         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.channel_mask = a_buffer->channel_mask;
2269         audio_stream.data_size = a_buffer->data_size;
2270         audio_stream.data = a_buffer->pcm_data;
2271         audio_stream.pcm_format = a_buffer->pcm_format;
2272 #ifdef __DEBUG__
2273         LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2274 #endif
2275         player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2276
2277         MMPLAYER_FLEAVE();
2278 }
2279
2280 static void
2281 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2282 {
2283         mmplayer_t *player = (mmplayer_t *)data;
2284         const gchar *pcm_format = NULL;
2285         gint channel = 0;
2286         gint rate = 0;
2287         guint64 channel_mask = 0;
2288         void *a_data = NULL;
2289         gint a_size = 0;
2290         mmplayer_audio_stream_buff_t *a_buffer = NULL;
2291         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2292         GList *l = NULL;
2293
2294         MMPLAYER_FENTER();
2295         MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2296
2297         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2298         a_data = mapinfo.data;
2299         a_size = mapinfo.size;
2300
2301         GstCaps *caps = gst_pad_get_current_caps(pad);
2302         GstStructure *structure = gst_caps_get_structure(caps, 0);
2303 #ifdef __DEBUG__
2304         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2305 #endif
2306         pcm_format = gst_structure_get_string(structure, "format");
2307         gst_structure_get_int(structure, "rate", &rate);
2308         gst_structure_get_int(structure, "channels", &channel);
2309         gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2310         gst_caps_unref(GST_CAPS(caps));
2311
2312         /* In case of the sync is false, use buffer list.              *
2313          * The num of buffer list depends on the num of audio channels */
2314         if (player->audio_stream_buff_list) {
2315                 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2316                         mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2317                         if (tmp) {
2318                                 if (channel_mask == tmp->channel_mask) {
2319 #ifdef __DEBUG__
2320                                         LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2321 #endif
2322                                         if (tmp->data_size + a_size < tmp->buff_size) {
2323                                                 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2324                                                 tmp->data_size += a_size;
2325                                         } else {
2326                                                 /* send data to client */
2327                                                 __mmplayer_audio_stream_send_data(player, tmp);
2328
2329                                                 if (a_size > tmp->buff_size) {
2330                                                         LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2331                                                         tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2332                                                         if (tmp->pcm_data == NULL) {
2333                                                                 LOGE("failed to realloc data.");
2334                                                                 goto DONE;
2335                                                         }
2336                                                         tmp->buff_size = a_size;
2337                                                 }
2338                                                 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2339                                                 memcpy(tmp->pcm_data, a_data, a_size);
2340                                                 tmp->data_size = a_size;
2341                                         }
2342                                         goto DONE;
2343                                 }
2344                         } else {
2345                                 LOGE("data is empty in list.");
2346                                 goto DONE;
2347                         }
2348                 }
2349         }
2350
2351         /* create new audio stream data for newly found audio channel */
2352         a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2353         if (a_buffer == NULL) {
2354                 LOGE("failed to alloc data.");
2355                 goto DONE;
2356         }
2357         a_buffer->bitrate = rate;
2358         a_buffer->channel = channel;
2359         a_buffer->channel_mask = channel_mask;
2360         a_buffer->data_size = a_size;
2361         a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2362
2363         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2364                 /* If sync is FALSE, use buffer list to reduce the IPC. */
2365                 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2366                 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2367                 if (a_buffer->pcm_data == NULL) {
2368                         LOGE("failed to alloc data.");
2369                         MMPLAYER_FREEIF(a_buffer);
2370                         goto DONE;
2371                 }
2372                 memcpy(a_buffer->pcm_data, a_data, a_size);
2373 #ifdef __DEBUG__
2374                 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2375 #endif
2376                 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2377         } else {
2378                 /* If sync is TRUE, send data directly. */
2379                 a_buffer->pcm_data = a_data;
2380                 __mmplayer_audio_stream_send_data(player, a_buffer);
2381                 MMPLAYER_FREEIF(a_buffer);
2382         }
2383
2384 DONE:
2385         gst_buffer_unmap(buffer, &mapinfo);
2386         MMPLAYER_FLEAVE();
2387 }
2388
2389 static void
2390 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2391 {
2392         mmplayer_t *player = (mmplayer_t *)data;
2393         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2394         GstPad *sinkpad = NULL;
2395         GstElement *queue = NULL, *sink = NULL;
2396
2397         MMPLAYER_FENTER();
2398         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2399
2400         queue = gst_element_factory_make("queue", NULL);
2401         if (queue == NULL) {
2402                 LOGD("fail make queue");
2403                 goto ERROR;
2404         }
2405
2406         sink = gst_element_factory_make("fakesink", NULL);
2407         if (sink == NULL) {
2408                 LOGD("fail make fakesink");
2409                 goto ERROR;
2410         }
2411
2412         gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2413
2414         if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2415                 LOGW("failed to link queue & sink");
2416                 goto ERROR;
2417         }
2418
2419         sinkpad = gst_element_get_static_pad(queue, "sink");
2420
2421         if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2422                 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2423                 goto ERROR;
2424         }
2425
2426         LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2427
2428         gst_object_unref(sinkpad);
2429         if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2430                 g_object_set(sink, "sync", TRUE, NULL);
2431         g_object_set(sink, "signal-handoffs", TRUE, NULL);
2432
2433         /* keep the first sink reference only */
2434         if (!audiobin[MMPLAYER_A_SINK].gst) {
2435                 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2436                 audiobin[MMPLAYER_A_SINK].gst = sink;
2437         }
2438
2439
2440         _mmplayer_add_signal_connection(player,
2441                 G_OBJECT(sink),
2442                 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2443                 "handoff",
2444                 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2445                 (gpointer)player);
2446
2447         __mmplayer_add_sink(player, sink);
2448
2449         if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2450                 LOGE("failed to sync state");
2451                 goto ERROR;
2452         }
2453
2454         if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2455                 LOGE("failed to sync state");
2456                 goto ERROR;
2457         }
2458
2459         MMPLAYER_FLEAVE();
2460         return;
2461
2462 ERROR:
2463         LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2464         if (queue) {
2465                 gst_object_unref(GST_OBJECT(queue));
2466                 queue = NULL;
2467         }
2468         if (sink) {
2469                 gst_object_unref(GST_OBJECT(sink));
2470                 sink = NULL;
2471         }
2472         if (sinkpad) {
2473                 gst_object_unref(GST_OBJECT(sinkpad));
2474                 sinkpad = NULL;
2475         }
2476
2477         return;
2478 }
2479
2480 void
2481 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2482 {
2483         mmplayer_t *player = (mmplayer_t *)data;
2484
2485         MMPLAYER_FENTER();
2486         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2487
2488         player->no_more_pad = TRUE;
2489         __mmplayer_pipeline_complete(NULL, player);
2490
2491         MMPLAYER_FLEAVE();
2492         return;
2493 }
2494
2495 void
2496 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2497 {
2498         #define MAX_PROPS_LEN 128
2499         mmplayer_gst_element_t *audiobin = NULL;
2500         gint latency_mode = 0;
2501         gchar *stream_type = NULL;
2502         gchar *latency = NULL;
2503         gint stream_id = 0;
2504         gchar stream_props[MAX_PROPS_LEN] = {0,};
2505         GstStructure *props = NULL;
2506
2507         /* set volume table
2508          * It should be set after player creation through attribute.
2509          * But, it can not be changed during playing.
2510          */
2511         MMPLAYER_FENTER();
2512         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2513
2514         audiobin = player->pipeline->audiobin;
2515
2516         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2517         if (player->sound.mute) {
2518                 LOGD("mute enabled");
2519                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2520         }
2521
2522         mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2523         mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2524
2525         if (!stream_type)
2526                 snprintf(stream_props, sizeof(stream_props) - 1,
2527                                 "props,application.process.id.origin=%d", player->client_pid);
2528         else
2529                 snprintf(stream_props, sizeof(stream_props) - 1,
2530                                 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2531                                 stream_type, stream_id, player->client_pid);
2532
2533         props = gst_structure_from_string(stream_props, NULL);
2534         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2535         LOGI("props result[%s].", stream_props);
2536         gst_structure_free(props);
2537
2538         mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2539
2540         switch (latency_mode) {
2541         case AUDIO_LATENCY_MODE_LOW:
2542                 latency = g_strndup("low", 3);
2543                 break;
2544         case AUDIO_LATENCY_MODE_MID:
2545                 latency = g_strndup("mid", 3);
2546                 break;
2547         case AUDIO_LATENCY_MODE_HIGH:
2548                 latency = g_strndup("high", 4);
2549                 break;
2550         };
2551
2552         g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2553
2554         LOGD("audiosink property - latency=%s", latency);
2555
2556         MMPLAYER_FREEIF(latency);
2557
2558         MMPLAYER_FLEAVE();
2559 }
2560
2561 void
2562 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2563 {
2564         mmplayer_gst_element_t *audiobin = NULL;
2565
2566         MMPLAYER_FENTER();
2567         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2568
2569         audiobin = player->pipeline->audiobin;
2570
2571         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2572         sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2573         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2574
2575         if (player->video360_yaw_radians <= M_PI &&
2576                         player->video360_yaw_radians >= -M_PI &&
2577                         player->video360_pitch_radians <= M_PI_2 &&
2578                         player->video360_pitch_radians >= -M_PI_2) {
2579                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2580                                 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2581                                 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2582         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2583                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2584                                 "source-orientation-y", player->video360_metadata.init_view_heading,
2585                                 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2586         }
2587
2588         MMPLAYER_FLEAVE();
2589 }
2590
2591 static int
2592 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2593 {
2594         mmplayer_gst_element_t *audiobin = NULL;
2595         GstPad *sink_pad = NULL;
2596         GstCaps *acaps = NULL;
2597         gint channels = 0;
2598         int pitch_control = 0;
2599         double pitch_value = 1.0;
2600
2601         MMPLAYER_FENTER();
2602         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2603                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2604
2605         audiobin = player->pipeline->audiobin;
2606
2607         LOGD("make element for normal audio playback");
2608
2609         /* audio bin structure for playback. {} means optional.
2610            optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2611
2612          * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2613                         {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2614          */
2615
2616         /* for pitch control */
2617         mm_attrs_multiple_get(player->attrs, NULL,
2618                                 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2619                                 MM_PLAYER_PITCH_VALUE, &pitch_value,
2620                                 NULL);
2621
2622         LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2623         if (pitch_control && (player->videodec_linked == 0)) {
2624                 GstElementFactory *factory;
2625
2626                 factory = gst_element_factory_find("pitch");
2627                 if (factory) {
2628                         gst_object_unref(factory);
2629
2630                         /* converter */
2631                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2632
2633                         /* pitch */
2634                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2635                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2636                 } else {
2637                         LOGW("there is no pitch element");
2638                 }
2639         }
2640
2641         /* converter */
2642         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2643
2644         /* replaygain volume */
2645         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2646         if (player->sound.rg_enable)
2647                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2648         else
2649                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2650
2651         /* resampler */
2652         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER,  player->ini.audioresampler_element, "audio resampler", *bucket, player);
2653
2654         if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2655                 /* currently, only openalsink uses volume element */
2656                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2657                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2658
2659                 if (player->sound.mute) {
2660                         LOGD("mute enabled");
2661                         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2662                 }
2663         }
2664
2665         mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2666
2667         /* audio effect element. if audio effect is enabled */
2668         if ((strcmp(player->ini.audioeffect_element, ""))
2669                 && (channels <= 2)
2670                 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2671                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2672
2673                 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2674
2675                 if ((!player->bypass_audio_effect)
2676                         && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2677                         if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2678                                 if (!_mmplayer_audio_effect_custom_apply(player))
2679                                         LOGI("apply audio effect(custom) setting success");
2680                         }
2681                 }
2682
2683                 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2684                         && (player->set_mode.rich_audio)) {
2685                         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2686                 }
2687         }
2688
2689         /* create audio sink */
2690         LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2691                         player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2692                         player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2693
2694         /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2695         if (player->is_360_feature_enabled &&
2696                 player->is_content_spherical &&
2697                 channels == 4 &&
2698                 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2699                 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2700                 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2701
2702                 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2703
2704                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2705
2706                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2707                 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2708                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2709                 gst_caps_unref(acaps);
2710
2711                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2712
2713                 player->is_openal_plugin_used = TRUE;
2714         } else {
2715                 if (player->is_360_feature_enabled && player->is_content_spherical)
2716                         LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2717                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2718         }
2719
2720         if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2721                 (player->videodec_linked && player->ini.use_system_clock)) {
2722                 LOGD("system clock will be used.");
2723                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE,  NULL);
2724         }
2725
2726         if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2727                 __mmplayer_gst_set_pulsesink_property(player);
2728         else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2729                 __mmplayer_gst_set_openalsink_property(player);
2730
2731         /* qos on */
2732         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL);       /* qos on */
2733         g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2734
2735         sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2736         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2737                                 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2738         gst_object_unref(GST_OBJECT(sink_pad));
2739
2740         __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2741
2742         MMPLAYER_FLEAVE();
2743         return MM_ERROR_NONE;
2744
2745 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2746         MMPLAYER_FLEAVE();
2747         return MM_ERROR_PLAYER_INTERNAL;
2748 }
2749
2750 static int
2751 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2752 {
2753         mmplayer_gst_element_t *audiobin = NULL;
2754         enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2755
2756         gchar *dst_format = NULL;
2757         int dst_len = 0;
2758         int dst_samplerate = 0;
2759         int dst_channels = 0;
2760         GstCaps *caps = NULL;
2761         char *caps_str = NULL;
2762
2763         MMPLAYER_FENTER();
2764         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2765                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2766
2767         audiobin = player->pipeline->audiobin;
2768
2769         LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2770
2771         /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2772
2773            [case 1] extract interleave audio pcm without playback
2774                                 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2775                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2776
2777                                 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2778
2779            [case 2] deinterleave for each channel without playback
2780                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2781                                   MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2782
2783                                 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2784                                                                                                                                                    - fakesink (sync or not)
2785                                                                                                                                                    - ...      (sync or not)
2786
2787            [case 3] [case 1(sync only)] + playback
2788                                 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2789
2790                                 * src - ... - tee - queue1 - playback path
2791                                                                   - queue2 - [case1 pipeline with sync]
2792
2793            [case 4] [case 2(sync only)] + playback
2794                                 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2795
2796                                 * src - ... - tee - queue1 - playback path
2797                                                                   - queue2 - [case2 pipeline with sync]
2798
2799          */
2800
2801         /* 1. create tee and playback path
2802               'tee' should be added at first to copy the decoded stream
2803          */
2804         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2805                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2806                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2807
2808                 /* tee - path 1 : for playback path */
2809                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2810                 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2811
2812                 /* tee - path 2 : for extract path */
2813                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2814                 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2815         }
2816
2817         /* if there is tee, 'tee - path 2' is linked here */
2818         /* converter */
2819         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2820
2821         /* resampler */
2822         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER,  player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2823
2824         /* 2. decide the extract pcm format */
2825         mm_attrs_multiple_get(player->attrs, NULL,
2826                                 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2827                                 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2828                                 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2829                                 NULL);
2830
2831         LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2832                         dst_format, dst_len, dst_samplerate, dst_channels);
2833
2834         if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2835                 mm_attrs_multiple_get(player->attrs, NULL,
2836                                         "content_audio_format", &dst_format, &dst_len, /* get string and len */
2837                                         "content_audio_samplerate", &dst_samplerate,
2838                                         "content_audio_channels", &dst_channels,
2839                                         NULL);
2840
2841                 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2842                                 dst_format, dst_len, dst_samplerate, dst_channels);
2843
2844                 /* If there is no enough information, set it to platform default value. */
2845                 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2846                         LOGD("set platform default format");
2847                         dst_format = DEFAULT_PCM_OUT_FORMAT;
2848                 }
2849                 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2850                 if (dst_channels <= 0)   dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2851         }
2852
2853         /* 3. create capsfilter */
2854         MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2855         caps = gst_caps_new_simple("audio/x-raw",
2856                         "format", G_TYPE_STRING, dst_format,
2857                         "rate", G_TYPE_INT, dst_samplerate,
2858                         "channels", G_TYPE_INT, dst_channels,
2859                         NULL);
2860
2861         caps_str = gst_caps_to_string(caps);
2862         LOGD("new caps : %s", caps_str);
2863
2864         g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2865
2866         /* clean */
2867         gst_caps_unref(caps);
2868         MMPLAYER_FREEIF(caps_str);
2869
2870         /* 4-1. create deinterleave to extract pcm for each channel */
2871         if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2872                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2873                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2874
2875                 /* audiosink will be added after getting signal for each channel */
2876                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2877                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2878                 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2879                                 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2880                 player->no_more_pad = FALSE;
2881         } else {
2882         /* 4-2. create fakesink to extract interlevaed pcm */
2883                 LOGD("add audio fakesink for interleaved audio");
2884                 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2885                 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2886                         g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2887                 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2888
2889                 _mmplayer_add_signal_connection(player,
2890                         G_OBJECT(audiobin[extract_sink_id].gst),
2891                         MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2892                         "handoff",
2893                         G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2894                         (gpointer)player);
2895
2896                 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2897         }
2898
2899         MMPLAYER_FLEAVE();
2900         return MM_ERROR_NONE;
2901
2902 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2903         MMPLAYER_FLEAVE();
2904         return MM_ERROR_PLAYER_INTERNAL;
2905 }
2906
2907 static int
2908 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2909 {
2910         int ret = MM_ERROR_NONE;
2911         mmplayer_gst_element_t *audiobin = NULL;
2912         GList *element_bucket = NULL;
2913
2914         MMPLAYER_FENTER();
2915         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2916                                 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2917
2918         audiobin = player->pipeline->audiobin;
2919
2920         if (player->build_audio_offload) { /* skip all the audio filters */
2921                 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2922
2923                 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2924                 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2925                                 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2926
2927                 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2928                 goto DONE;
2929         }
2930
2931         /* FIXME: need to mention the supportable condition at API reference */
2932         if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2933                 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2934         else
2935                 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2936
2937         if (ret != MM_ERROR_NONE)
2938                 goto ERROR;
2939 DONE:
2940         LOGD("success to make audio bin element");
2941         *bucket = element_bucket;
2942
2943         MMPLAYER_FLEAVE();
2944         return MM_ERROR_NONE;
2945
2946 ERROR:
2947         LOGE("failed to make audio bin element");
2948         g_list_free(element_bucket);
2949
2950         *bucket = NULL;
2951         MMPLAYER_FLEAVE();
2952         return MM_ERROR_PLAYER_INTERNAL;
2953 }
2954
2955 static int
2956 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2957 {
2958         mmplayer_gst_element_t *first_element = NULL;
2959         mmplayer_gst_element_t *audiobin = NULL;
2960         GstPad *pad = NULL;
2961         GstPad *ghostpad = NULL;
2962         GList *element_bucket = NULL;
2963         int i = 0;
2964
2965         MMPLAYER_FENTER();
2966         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2967
2968         /* alloc handles */
2969         audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2970         if (!audiobin) {
2971                 LOGE("failed to allocate memory for audiobin");
2972                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2973         }
2974
2975         /* create bin */
2976         audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2977         audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2978         if (!audiobin[MMPLAYER_A_BIN].gst) {
2979                 LOGE("failed to create audiobin");
2980                 goto ERROR;
2981         }
2982
2983         /* take it */
2984         player->pipeline->audiobin = audiobin;
2985
2986         /* create audio filters and audiosink */
2987         if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2988                 goto ERROR;
2989
2990         /* adding created elements to bin */
2991         LOGD("adding created elements to bin");
2992         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2993                 goto ERROR;
2994
2995         /* linking elements in the bucket by added order. */
2996         LOGD("Linking elements in the bucket by added order.");
2997         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
2998                 goto ERROR;
2999
3000         /* get first element's sinkpad for creating ghostpad */
3001         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3002         if (!first_element) {
3003                 LOGE("failed to get first elem");
3004                 goto ERROR;
3005         }
3006
3007         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3008         if (!pad) {
3009                 LOGE("failed to get pad from first element of audiobin");
3010                 goto ERROR;
3011         }
3012
3013         ghostpad = gst_ghost_pad_new("sink", pad);
3014         if (!ghostpad) {
3015                 LOGE("failed to create ghostpad");
3016                 goto ERROR;
3017         }
3018
3019         if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3020                 LOGE("failed to add ghostpad to audiobin");
3021                 goto ERROR;
3022         }
3023
3024         gst_object_unref(pad);
3025
3026         g_list_free(element_bucket);
3027         MMPLAYER_FLEAVE();
3028
3029         return MM_ERROR_NONE;
3030
3031 ERROR:
3032         LOGD("ERROR : releasing audiobin");
3033
3034         if (pad)
3035                 gst_object_unref(GST_OBJECT(pad));
3036
3037         if (ghostpad)
3038                 gst_object_unref(GST_OBJECT(ghostpad));
3039
3040         if (element_bucket)
3041                 g_list_free(element_bucket);
3042
3043         /* release element which are not added to bin */
3044         for (i = 1; i < MMPLAYER_A_NUM; i++) {
3045                 /* NOTE : skip bin */
3046                 if (audiobin[i].gst) {
3047                         GstObject *parent = NULL;
3048                         parent = gst_element_get_parent(audiobin[i].gst);
3049
3050                         if (!parent) {
3051                                 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3052                                 audiobin[i].gst = NULL;
3053                         } else
3054                                 gst_object_unref(GST_OBJECT(parent));
3055                 }
3056         }
3057
3058         /* release audiobin with it's childs */
3059         if (audiobin[MMPLAYER_A_BIN].gst)
3060                 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3061
3062         MMPLAYER_FREEIF(audiobin);
3063
3064         player->pipeline->audiobin = NULL;
3065
3066         return MM_ERROR_PLAYER_INTERNAL;
3067 }
3068
3069 static guint32
3070 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3071 {
3072         return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3073 }
3074
3075 int
3076 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3077 {
3078         int ret = MM_ERROR_NONE;
3079         GList *l = NULL;
3080         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3081         MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3082
3083         MMPLAYER_VIDEO_BO_LOCK(player);
3084
3085         if (player->video_bo_list) {
3086                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3087                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3088                         if (tmp && tmp->bo == bo) {
3089                                 tmp->used = FALSE;
3090                                 LOGD("release bo %p", bo);
3091                                 tbm_bo_unref(tmp->bo);
3092                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3093                                 MMPLAYER_VIDEO_BO_SIGNAL(player);
3094                                 return ret;
3095                         }
3096                 }
3097         } else {
3098                 /* hw codec is running or the list was reset for DRC. */
3099                 LOGW("there is no bo list.");
3100         }
3101         MMPLAYER_VIDEO_BO_UNLOCK(player);
3102
3103         LOGW("failed to find bo %p", bo);
3104         return ret;
3105 }
3106
3107 static void
3108 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3109 {
3110         GList *l = NULL;
3111
3112         MMPLAYER_FENTER();
3113         MMPLAYER_RETURN_IF_FAIL(player);
3114
3115         MMPLAYER_VIDEO_BO_LOCK(player);
3116         if (player->video_bo_list) {
3117                 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3118                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3119                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3120                         if (tmp) {
3121                                 if (tmp->bo)
3122                                         tbm_bo_unref(tmp->bo);
3123                                 g_free(tmp);
3124                         }
3125                 }
3126                 g_list_free(player->video_bo_list);
3127                 player->video_bo_list = NULL;
3128         }
3129         player->video_bo_size = 0;
3130         MMPLAYER_VIDEO_BO_UNLOCK(player);
3131
3132         MMPLAYER_FLEAVE();
3133         return;
3134 }
3135
3136 static void *
3137 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3138 {
3139         GList *l = NULL;
3140         MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3141         gboolean ret = TRUE;
3142
3143         /* check DRC, if it is, destroy the prev bo list to create again */
3144         if (player->video_bo_size != size) {
3145                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3146                 __mmplayer_video_stream_destroy_bo_list(player);
3147                 player->video_bo_size = size;
3148         }
3149
3150         MMPLAYER_VIDEO_BO_LOCK(player);
3151
3152         if ((!player->video_bo_list) ||
3153                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3154
3155                 /* create bo list */
3156                 int idx = 0;
3157                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3158
3159                 if (player->video_bo_list) {
3160                         /* if bo list did not created all, try it again. */
3161                         idx = g_list_length(player->video_bo_list);
3162                         LOGD("bo list exist(len: %d)", idx);
3163                 }
3164
3165                 for (; idx < player->ini.num_of_video_bo; idx++) {
3166                         mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3167                         if (!bo_info) {
3168                                 LOGE("Fail to alloc bo_info.");
3169                                 break;
3170                         }
3171                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3172                         if (!bo_info->bo) {
3173                                 LOGE("Fail to tbm_bo_alloc.");
3174                                 MMPLAYER_FREEIF(bo_info);
3175                                 break;
3176                         }
3177                         bo_info->used = FALSE;
3178                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3179                 }
3180
3181                 /* update video num buffers */
3182                 LOGD("video_num_buffers : %d", idx);
3183                 mm_player_set_attribute((MMHandleType)player, NULL,
3184                                 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3185                                 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3186                                 NULL);
3187
3188                 if (idx == 0) {
3189                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3190                         return NULL;
3191                 }
3192         }
3193
3194         while (TRUE) {
3195                 /* get bo from list*/
3196                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3197                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3198                         if (tmp && (tmp->used == FALSE)) {
3199                                 LOGD("found bo %p to use", tmp->bo);
3200                                 tmp->used = TRUE;
3201                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3202                                 return tbm_bo_ref(tmp->bo);
3203                         }
3204                 }
3205                 if (!ret) {
3206                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3207                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3208                         return NULL;
3209                 }
3210
3211                 if (player->ini.video_bo_timeout <= 0) {
3212                         MMPLAYER_VIDEO_BO_WAIT(player);
3213                 } else {
3214                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3215                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3216                 }
3217                 continue;
3218         }
3219 }
3220
3221 static void
3222 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3223 {
3224         mmplayer_t *player = (mmplayer_t *)data;
3225         MMPLAYER_FENTER();
3226         MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3227
3228         /* send prerolled pkt */
3229         player->video_stream_prerolled = false;
3230
3231         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3232
3233         /* not to send prerolled pkt again */
3234         player->video_stream_prerolled = true;
3235 }
3236
3237 static void
3238 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3239 {
3240         mmplayer_t *player = (mmplayer_t *)data;
3241         mmplayer_video_decoded_data_info_t *stream = NULL;
3242         GstMemory *mem = NULL;
3243
3244         MMPLAYER_FENTER();
3245         MMPLAYER_RETURN_IF_FAIL(player);
3246         MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3247
3248         if (player->video_stream_prerolled) {
3249                 player->video_stream_prerolled = false;
3250                 LOGD("skip the prerolled pkt not to send it again");
3251                 return;
3252         }
3253
3254         /* clear stream data structure */
3255         stream = __mmplayer_create_stream_from_pad(pad);
3256         if (!stream) {
3257                 LOGE("failed to alloc stream");
3258                 return;
3259         }
3260
3261         _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3262
3263         /* set size and timestamp */
3264         mem = gst_buffer_peek_memory(buffer, 0);
3265         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3266         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3267
3268         /* check zero-copy */
3269         if (player->set_mode.video_zc &&
3270                 player->set_mode.video_export &&
3271                 gst_is_tizen_memory(mem)) {
3272                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3273                 stream->internal_buffer = gst_buffer_ref(buffer);
3274         } else { /* sw codec */
3275                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3276                         goto ERROR;
3277
3278                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3279                         goto ERROR;
3280         }
3281
3282         if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3283                 LOGE("failed to send video decoded data.");
3284                 goto ERROR;
3285         }
3286
3287         return;
3288
3289 ERROR:
3290         LOGE("release video stream resource.");
3291         if (gst_is_tizen_memory(mem)) {
3292                 int i = 0;
3293                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3294                         if (stream->bo[i])
3295                                 tbm_bo_unref(stream->bo[i]);
3296                 }
3297
3298                 /* unref gst buffer */
3299                 if (stream->internal_buffer)
3300                         gst_buffer_unref(stream->internal_buffer);
3301         } else {
3302                 if (stream->bo[0])
3303                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3304         }
3305         MMPLAYER_FREEIF(stream);
3306         return;
3307 }
3308
3309 static void
3310 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3311 {
3312         mmplayer_gst_element_t *videobin = NULL;
3313
3314         MMPLAYER_FENTER();
3315         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3316
3317         videobin = player->pipeline->videobin;
3318
3319         /* Set spatial media metadata and/or user settings to the element.
3320          * */
3321         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3322                         "projection-type", player->video360_metadata.projection_type, NULL);
3323
3324         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3325                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3326
3327         if (player->video360_metadata.full_pano_width_pixels &&
3328                         player->video360_metadata.full_pano_height_pixels &&
3329                         player->video360_metadata.cropped_area_image_width &&
3330                         player->video360_metadata.cropped_area_image_height) {
3331                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3332                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3333                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3334                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3335                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3336                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3337                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3338                                 NULL);
3339         }
3340
3341         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3342                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343                                 "horizontal-fov", player->video360_horizontal_fov,
3344                                 "vertical-fov", player->video360_vertical_fov, NULL);
3345         }
3346
3347         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3348                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3349                                 "zoom", 1.0f / player->video360_zoom, NULL);
3350         }
3351
3352         if (player->video360_yaw_radians <= M_PI &&
3353                         player->video360_yaw_radians >= -M_PI &&
3354                         player->video360_pitch_radians <= M_PI_2 &&
3355                         player->video360_pitch_radians >= -M_PI_2) {
3356                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357                                 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3358                                 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3359         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3360                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3361                                 "pose-yaw", player->video360_metadata.init_view_heading,
3362                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3363         }
3364
3365         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366                         "passthrough", !player->is_video360_enabled, NULL);
3367
3368
3369         MMPLAYER_FLEAVE();
3370 }
3371
3372 static int
3373 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3374 {
3375         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3376         GList *element_bucket = NULL;
3377
3378         MMPLAYER_FENTER();
3379         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3380
3381         /* create video360 filter */
3382         if (player->is_360_feature_enabled && player->is_content_spherical) {
3383                 LOGD("create video360 element");
3384                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3385                 __mmplayer_gst_set_video360_property(player);
3386                 goto EXIT;
3387         }
3388
3389         if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3390                 LOGD("skip creating the videoconv and rotator");
3391                 return MM_ERROR_NONE;
3392         }
3393
3394         /* in case of sw codec & overlay surface type, except 360 playback.
3395          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3396         LOGD("create video converter: %s", video_csc);
3397         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3398
3399 EXIT:
3400         *bucket = element_bucket;
3401         MMPLAYER_FLEAVE();
3402         return MM_ERROR_NONE;
3403
3404 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3405         g_list_free(element_bucket);
3406
3407         *bucket = NULL;
3408         MMPLAYER_FLEAVE();
3409         return MM_ERROR_PLAYER_INTERNAL;
3410 }
3411
3412 static gchar *
3413 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3414 {
3415         gchar *factory_name = NULL;
3416
3417         switch (surface_type) {
3418         case MM_DISPLAY_SURFACE_OVERLAY:
3419                 if (strlen(player->ini.videosink_element_overlay) > 0)
3420                         factory_name = player->ini.videosink_element_overlay;
3421                 break;
3422         case MM_DISPLAY_SURFACE_REMOTE:
3423         case MM_DISPLAY_SURFACE_NULL:
3424                 if (strlen(player->ini.videosink_element_fake) > 0)
3425                         factory_name = player->ini.videosink_element_fake;
3426                 break;
3427         default:
3428                 LOGE("unidentified surface type");
3429                 break;
3430         }
3431
3432         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3433         return factory_name;
3434 }
3435
3436 static int
3437 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3438 {
3439         gchar *factory_name = NULL;
3440         mmplayer_gst_element_t *videobin = NULL;
3441         MMHandleType attrs;
3442         int gapless = 0;
3443
3444         MMPLAYER_FENTER();
3445         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3446
3447         videobin = player->pipeline->videobin;
3448         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3449
3450         attrs = MMPLAYER_GET_ATTRS(player);
3451         if (!attrs) {
3452                 LOGE("cannot get content attribute");
3453                 return MM_ERROR_PLAYER_INTERNAL;
3454         }
3455
3456         LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3457         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3458                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3459                 if (!use_tbm) {
3460                         /* support shard memory with S/W codec on HawkP */
3461                         if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3462                                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3463                                         "use-tbm", use_tbm, NULL);
3464                         }
3465                 }
3466
3467                 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3468                         return MM_ERROR_PLAYER_INTERNAL;
3469         } else {
3470                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3471                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3472         }
3473
3474         mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3475         if (gapless > 0) {
3476                 LOGD("disable last-sample");
3477                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3478         }
3479
3480         if (player->set_mode.video_export) {
3481                 int enable = 0;
3482                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3483                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3484                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3485
3486                 _mmplayer_add_signal_connection(player,
3487                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3488                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3489                                                                 "handoff",
3490                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3491                                                                 (gpointer)player);
3492
3493                 _mmplayer_add_signal_connection(player,
3494                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3495                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3496                                                                 "preroll-handoff",
3497                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3498                                                                 (gpointer)player);
3499         }
3500
3501         if (videobin[MMPLAYER_V_SINK].gst) {
3502                 GstPad *sink_pad = NULL;
3503                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3504                 if (sink_pad) {
3505                         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3506                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3507                         gst_object_unref(GST_OBJECT(sink_pad));
3508                 } else {
3509                         LOGE("failed to get sink pad from videosink");
3510                 }
3511         }
3512
3513         return MM_ERROR_NONE;
3514 }
3515
3516 /**
3517  * VIDEO BIN
3518  * - video overlay surface(arm/x86) : tizenwlsink
3519  */
3520 static int
3521 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3522 {
3523         GstPad *pad = NULL;
3524         GList *element_bucket = NULL;
3525         mmplayer_gst_element_t *first_element = NULL;
3526         mmplayer_gst_element_t *videobin = NULL;
3527         gchar *videosink_factory_name = NULL;
3528
3529         MMPLAYER_FENTER();
3530         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3531
3532         /* alloc handles */
3533         videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3534         if (!videobin)
3535                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3536
3537         player->pipeline->videobin = videobin;
3538
3539         /* create bin */
3540         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3541         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3542         if (!videobin[MMPLAYER_V_BIN].gst) {
3543                 LOGE("failed to create videobin");
3544                 goto ERROR;
3545         }
3546
3547         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3548                 goto ERROR;
3549
3550         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3551         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3552
3553         /* additional setting for sink plug-in */
3554         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3555                 LOGE("failed to set video property");
3556                 goto ERROR;
3557         }
3558
3559         /* store it as it's sink element */
3560         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3561
3562         /* adding created elements to bin */
3563         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3564                 LOGE("failed to add elements");
3565                 goto ERROR;
3566         }
3567
3568         /* Linking elements in the bucket by added order */
3569         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3570                 LOGE("failed to link elements");
3571                 goto ERROR;
3572         }
3573
3574         /* get first element's sinkpad for creating ghostpad */
3575         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3576         if (!first_element) {
3577                 LOGE("failed to get first element from bucket");
3578                 goto ERROR;
3579         }
3580
3581         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3582         if (!pad) {
3583                 LOGE("failed to get pad from first element");
3584                 goto ERROR;
3585         }
3586
3587         /* create ghostpad */
3588         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3589         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3590                 LOGE("failed to add ghostpad to videobin");
3591                 goto ERROR;
3592         }
3593         gst_object_unref(pad);
3594
3595         /* done. free allocated variables */
3596         g_list_free(element_bucket);
3597
3598         MMPLAYER_FLEAVE();
3599
3600         return MM_ERROR_NONE;
3601
3602 ERROR:
3603         LOGE("ERROR : releasing videobin");
3604         g_list_free(element_bucket);
3605
3606         if (pad)
3607                 gst_object_unref(GST_OBJECT(pad));
3608
3609         /* release videobin with it's childs */
3610         if (videobin[MMPLAYER_V_BIN].gst)
3611                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3612
3613         MMPLAYER_FREEIF(videobin);
3614         player->pipeline->videobin = NULL;
3615
3616         return MM_ERROR_PLAYER_INTERNAL;
3617 }
3618
3619 static int
3620 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3621 {
3622         GList *element_bucket = NULL;
3623         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3624
3625         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3626         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3627         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3628                                                         "signal-handoffs", FALSE,
3629                                                         NULL);
3630
3631         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3632         _mmplayer_add_signal_connection(player,
3633                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3634                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3635                                                         "handoff",
3636                                                         G_CALLBACK(__mmplayer_update_subtitle),
3637                                                         (gpointer)player);
3638
3639         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3640                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3641
3642         if (!player->play_subtitle) {
3643                 LOGD("add textbin sink as sink element of whole pipeline.");
3644                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3645         }
3646
3647         /* adding created elements to bin */
3648         LOGD("adding created elements to bin");
3649         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3650                 LOGE("failed to add elements");
3651                 goto ERROR;
3652         }
3653
3654         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3655         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3656         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3657
3658         /* linking elements in the bucket by added order. */
3659         LOGD("Linking elements in the bucket by added order.");
3660         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3661                 LOGE("failed to link elements");
3662                 goto ERROR;
3663         }
3664
3665         /* done. free allocated variables */
3666         g_list_free(element_bucket);
3667
3668         if (textbin[MMPLAYER_T_QUEUE].gst) {
3669                 GstPad *pad = NULL;
3670                 GstPad *ghostpad = NULL;
3671
3672                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3673                 if (!pad) {
3674                         LOGE("failed to get sink pad of text queue");
3675                         goto ERROR;
3676                 }
3677
3678                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3679                 gst_object_unref(pad);
3680
3681                 if (!ghostpad) {
3682                         LOGE("failed to create ghostpad of textbin");
3683                         goto ERROR;
3684                 }
3685
3686                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3687                         LOGE("failed to add ghostpad to textbin");
3688                         gst_object_unref(ghostpad);
3689                         goto ERROR;
3690                 }
3691         }
3692
3693         return MM_ERROR_NONE;
3694
3695 ERROR:
3696         g_list_free(element_bucket);
3697
3698         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3699                 LOGE("remove textbin sink from sink list");
3700                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3701         }
3702
3703         /* release element at __mmplayer_gst_create_text_sink_bin */
3704         return MM_ERROR_PLAYER_INTERNAL;
3705 }
3706
3707 static int
3708 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3709 {
3710         mmplayer_gst_element_t *textbin = NULL;
3711         GList *element_bucket = NULL;
3712         int surface_type = 0;
3713         gint i = 0;
3714
3715         MMPLAYER_FENTER();
3716
3717         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3718
3719         /* alloc handles */
3720         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3721         if (!textbin) {
3722                 LOGE("failed to allocate memory for textbin");
3723                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3724         }
3725
3726         /* create bin */
3727         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3728         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3729         if (!textbin[MMPLAYER_T_BIN].gst) {
3730                 LOGE("failed to create textbin");
3731                 goto ERROR;
3732         }
3733
3734         /* take it */
3735         player->pipeline->textbin = textbin;
3736
3737         /* fakesink */
3738         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3739         LOGD("surface type for subtitle : %d", surface_type);
3740         switch (surface_type) {
3741         case MM_DISPLAY_SURFACE_OVERLAY:
3742         case MM_DISPLAY_SURFACE_NULL:
3743         case MM_DISPLAY_SURFACE_REMOTE:
3744                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3745                         LOGE("failed to make plain text elements");
3746                         goto ERROR;
3747                 }
3748                 break;
3749         default:
3750                 goto ERROR;
3751                 break;
3752         }
3753
3754         MMPLAYER_FLEAVE();
3755
3756         return MM_ERROR_NONE;
3757
3758 ERROR:
3759
3760         LOGD("ERROR : releasing textbin");
3761
3762         g_list_free(element_bucket);
3763
3764         /* release signal */
3765         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3766
3767         /* release element which are not added to bin */
3768         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3769                 /* NOTE : skip bin */
3770                 if (textbin[i].gst) {
3771                         GstObject *parent = NULL;
3772                         parent = gst_element_get_parent(textbin[i].gst);
3773
3774                         if (!parent) {
3775                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3776                                 textbin[i].gst = NULL;
3777                         } else {
3778                                 gst_object_unref(GST_OBJECT(parent));
3779                         }
3780                 }
3781         }
3782
3783         /* release textbin with it's childs */
3784         if (textbin[MMPLAYER_T_BIN].gst)
3785                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3786
3787         MMPLAYER_FREEIF(player->pipeline->textbin);
3788         player->pipeline->textbin = NULL;
3789
3790         MMPLAYER_FLEAVE();
3791         return MM_ERROR_PLAYER_INTERNAL;
3792 }
3793
3794 static int
3795 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3796 {
3797         mmplayer_gst_element_t *mainbin = NULL;
3798         mmplayer_gst_element_t *textbin = NULL;
3799         MMHandleType attrs = 0;
3800         GstElement *subsrc = NULL;
3801         GstElement *subparse = NULL;
3802         gchar *subtitle_uri = NULL;
3803         const gchar *charset = NULL;
3804         GstPad *pad = NULL;
3805
3806         MMPLAYER_FENTER();
3807
3808         /* get mainbin */
3809         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3810                                                                 player->pipeline &&
3811                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3812
3813         mainbin = player->pipeline->mainbin;
3814
3815         attrs = MMPLAYER_GET_ATTRS(player);
3816         if (!attrs) {
3817                 LOGE("cannot get content attribute");
3818                 return MM_ERROR_PLAYER_INTERNAL;
3819         }
3820
3821         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3822         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3823                 LOGE("subtitle uri is not proper filepath.");
3824                 return MM_ERROR_PLAYER_INVALID_URI;
3825         }
3826
3827         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3828                 LOGE("failed to get storage info of subtitle path");
3829                 return MM_ERROR_PLAYER_INVALID_URI;
3830         }
3831
3832         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3833
3834         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3835         player->subtitle_language_list = NULL;
3836         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3837
3838         /* create the subtitle source */
3839         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3840         if (!subsrc) {
3841                 LOGE("failed to create filesrc element");
3842                 goto ERROR;
3843         }
3844         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3845
3846         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3847         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3848
3849         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3850                 LOGW("failed to add queue");
3851                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3852                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3853                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3854                 goto ERROR;
3855         }
3856
3857         /* subparse */
3858         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3859         if (!subparse) {
3860                 LOGE("failed to create subparse element");
3861                 goto ERROR;
3862         }
3863
3864         charset = _mmplayer_get_charset(subtitle_uri);
3865         if (charset) {
3866                 LOGD("detected charset is %s", charset);
3867                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3868         }
3869
3870         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3871         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3872
3873         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3874                 LOGW("failed to add subparse");
3875                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3876                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3877                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3878                 goto ERROR;
3879         }
3880
3881         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3882                 LOGW("failed to link subsrc and subparse");
3883                 goto ERROR;
3884         }
3885
3886         player->play_subtitle = TRUE;
3887         player->adjust_subtitle_pos = 0;
3888
3889         LOGD("play subtitle using subtitle file");
3890
3891         if (player->pipeline->textbin == NULL) {
3892                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3893                         LOGE("failed to create text sink bin. continuing without text");
3894                         goto ERROR;
3895                 }
3896
3897                 textbin = player->pipeline->textbin;
3898
3899                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3900                         LOGW("failed to add textbin");
3901
3902                         /* release signal */
3903                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3904
3905                         /* release textbin with it's childs */
3906                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3907                         MMPLAYER_FREEIF(player->pipeline->textbin);
3908                         player->pipeline->textbin = textbin = NULL;
3909                         goto ERROR;
3910                 }
3911
3912                 LOGD("link text input selector and textbin ghost pad");
3913
3914                 player->textsink_linked = 1;
3915                 player->external_text_idx = 0;
3916                 LOGI("textsink is linked");
3917         } else {
3918                 textbin = player->pipeline->textbin;
3919                 LOGD("text bin has been created. reuse it.");
3920                 player->external_text_idx = 1;
3921         }
3922
3923         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3924                 LOGW("failed to link subparse and textbin");
3925                 goto ERROR;
3926         }
3927
3928         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3929         if (!pad) {
3930                 LOGE("failed to get sink pad from textsink to probe data");
3931                 goto ERROR;
3932         }
3933
3934         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3935                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3936
3937         gst_object_unref(pad);
3938         pad = NULL;
3939
3940         /* create dot. for debugging */
3941         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3942         MMPLAYER_FLEAVE();
3943
3944         return MM_ERROR_NONE;
3945
3946 ERROR:
3947         /* release text pipeline resource */
3948         player->textsink_linked = 0;
3949
3950         /* release signal */
3951         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3952
3953         if (player->pipeline->textbin) {
3954                 LOGE("remove textbin");
3955
3956                 /* release textbin with it's childs */
3957                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3958                 MMPLAYER_FREEIF(player->pipeline->textbin);
3959                 player->pipeline->textbin = NULL;
3960
3961         }
3962
3963         /* release subtitle elem */
3964         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3965         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3966
3967         return MM_ERROR_PLAYER_INTERNAL;
3968 }
3969
3970 gboolean
3971 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3972 {
3973         mmplayer_t *player = (mmplayer_t *)data;
3974         MMMessageParamType msg = {0, };
3975         GstClockTime duration = 0;
3976         gpointer text = NULL;
3977         guint text_size = 0;
3978         gboolean ret = TRUE;
3979         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3980
3981         MMPLAYER_FENTER();
3982
3983         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3984         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3985
3986         if (player->is_subtitle_force_drop) {
3987                 LOGW("subtitle is dropped forcedly.");
3988                 return ret;
3989         }
3990
3991         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3992         text = mapinfo.data;
3993         text_size = mapinfo.size;
3994
3995         if (player->set_mode.subtitle_off) {
3996                 LOGD("subtitle is OFF.");
3997                 return TRUE;
3998         }
3999
4000         if (!text || (text_size == 0)) {
4001                 LOGD("There is no subtitle to be displayed.");
4002                 return TRUE;
4003         }
4004
4005         msg.data = (void *)text;
4006
4007         duration = GST_BUFFER_DURATION(buffer);
4008
4009         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4010                 if (player->duration > GST_BUFFER_PTS(buffer))
4011                         duration = player->duration - GST_BUFFER_PTS(buffer);
4012                 else
4013                         duration = 0;
4014                 LOGI("subtitle duration is invalid, subtitle duration change "
4015                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4016         }
4017         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4018
4019         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4020
4021         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4022         gst_buffer_unmap(buffer, &mapinfo);
4023
4024         MMPLAYER_FLEAVE();
4025
4026         return ret;
4027 }
4028
4029 static GstPadProbeReturn
4030 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4031 {
4032         mmplayer_t *player = (mmplayer_t *)u_data;
4033         GstClockTime cur_timestamp = 0;
4034         gint64 adjusted_timestamp = 0;
4035         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4036
4037         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4038
4039         if (player->set_mode.subtitle_off) {
4040                 LOGD("subtitle is OFF.");
4041                 return TRUE;
4042         }
4043
4044         if (player->adjust_subtitle_pos == 0) {
4045                 LOGD("nothing to do");
4046                 return TRUE;
4047         }
4048
4049         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4050         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4051
4052         if (adjusted_timestamp < 0) {
4053                 LOGD("adjusted_timestamp under zero");
4054                 MMPLAYER_FLEAVE();
4055                 return FALSE;
4056         }
4057
4058         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4059         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4060                                 GST_TIME_ARGS(cur_timestamp),
4061                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4062
4063         return GST_PAD_PROBE_OK;
4064 }
4065
4066 static int
4067 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4068 {
4069         MMPLAYER_FENTER();
4070
4071         /* check player and subtitlebin are created */
4072         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4073         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4074
4075         if (position == 0) {
4076                 LOGD("nothing to do");
4077                 MMPLAYER_FLEAVE();
4078                 return MM_ERROR_NONE;
4079         }
4080
4081         /* check current postion */
4082         player->adjust_subtitle_pos = position;
4083
4084         LOGD("save adjust_subtitle_pos in player");
4085
4086         MMPLAYER_FLEAVE();
4087
4088         return MM_ERROR_NONE;
4089 }
4090
4091 /**
4092  * This function is to create  audio or video pipeline for playing.
4093  *
4094  * @param       player          [in]    handle of player
4095  *
4096  * @return      This function returns zero on success.
4097  * @remark
4098  * @see
4099  */
4100 static int
4101 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4102 {
4103         int ret = MM_ERROR_NONE;
4104         mmplayer_gst_element_t *mainbin = NULL;
4105         MMHandleType attrs = 0;
4106
4107         MMPLAYER_FENTER();
4108         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4109
4110         /* get profile attribute */
4111         attrs = MMPLAYER_GET_ATTRS(player);
4112         if (!attrs) {
4113                 LOGE("failed to get content attribute");
4114                 goto INIT_ERROR;
4115         }
4116
4117         /* create pipeline handles */
4118         if (player->pipeline) {
4119                 LOGE("pipeline should be released before create new one");
4120                 goto INIT_ERROR;
4121         }
4122
4123         player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4124         if (player->pipeline == NULL)
4125                 goto INIT_ERROR;
4126
4127         /* create mainbin */
4128         mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4129         if (mainbin == NULL)
4130                 goto INIT_ERROR;
4131
4132         /* create pipeline */
4133         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4134         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4135         if (!mainbin[MMPLAYER_M_PIPE].gst) {
4136                 LOGE("failed to create pipeline");
4137                 g_free(mainbin);
4138                 goto INIT_ERROR;
4139         }
4140
4141         player->pipeline->mainbin = mainbin;
4142
4143         /* create the source and decoder elements */
4144         if (MMPLAYER_IS_MS_BUFF_SRC(player))
4145                 ret = _mmplayer_gst_build_es_pipeline(player);
4146         else
4147                 ret = _mmplayer_gst_build_pipeline(player);
4148
4149         if (ret != MM_ERROR_NONE) {
4150                 LOGE("failed to create some elements");
4151                 goto INIT_ERROR;
4152         }
4153
4154         /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4155         if (__mmplayer_check_subtitle(player)
4156                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4157                 LOGE("failed to create text pipeline");
4158
4159         /* add bus watch */
4160         ret = _mmplayer_gst_add_bus_watch(player);
4161         if (ret != MM_ERROR_NONE) {
4162                 LOGE("failed to add bus watch");
4163                 goto INIT_ERROR;
4164         }
4165
4166         MMPLAYER_FLEAVE();
4167         return MM_ERROR_NONE;
4168
4169 INIT_ERROR:
4170         __mmplayer_gst_destroy_pipeline(player);
4171         return MM_ERROR_PLAYER_INTERNAL;
4172 }
4173
4174 static void
4175 __mmplayer_reset_gapless_state(mmplayer_t *player)
4176 {
4177         MMPLAYER_FENTER();
4178         MMPLAYER_RETURN_IF_FAIL(player
4179                 && player->pipeline
4180                 && player->pipeline->audiobin
4181                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4182
4183         memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4184
4185         MMPLAYER_FLEAVE();
4186         return;
4187 }
4188
4189 static int
4190 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4191 {
4192         gint timeout = 0;
4193         int ret = MM_ERROR_NONE;
4194
4195         MMPLAYER_FENTER();
4196
4197         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4198
4199         /* cleanup stuffs */
4200         MMPLAYER_FREEIF(player->type);
4201         player->no_more_pad = FALSE;
4202         player->num_dynamic_pad = 0;
4203         player->demux_pad_index = 0;
4204
4205         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4206         player->subtitle_language_list = NULL;
4207         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4208
4209         __mmplayer_reset_gapless_state(player);
4210
4211         if (player->streamer) {
4212                 _mm_player_streaming_initialize(player->streamer, FALSE);
4213                 _mm_player_streaming_destroy(player->streamer);
4214                 player->streamer = NULL;
4215         }
4216
4217         /* cleanup unlinked mime type */
4218         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4219         MMPLAYER_FREEIF(player->unlinked_video_mime);
4220         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4221
4222         /* cleanup running stuffs */
4223         _mmplayer_cancel_eos_timer(player);
4224
4225         /* cleanup gst stuffs */
4226         if (player->pipeline) {
4227                 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4228                 GstTagList *tag_list = player->pipeline->tag_list;
4229
4230                 /* first we need to disconnect all signal hander */
4231                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4232
4233                 if (mainbin) {
4234                         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4235                         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4236                         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4237                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4238                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4239                         gst_object_unref(bus);
4240
4241                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4242                         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4243                         if (ret != MM_ERROR_NONE) {
4244                                 LOGE("fail to change state to NULL");
4245                                 return MM_ERROR_PLAYER_INTERNAL;
4246                         }
4247
4248                         LOGW("succeeded in changing state to NULL");
4249
4250                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4251
4252                         /* free fakesink */
4253                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4254                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4255
4256                         /* free avsysaudiosink
4257                            avsysaudiosink should be unref when destory pipeline just after start play with BT.
4258                            Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4259                         */
4260                         MMPLAYER_FREEIF(audiobin);
4261                         MMPLAYER_FREEIF(videobin);
4262                         MMPLAYER_FREEIF(textbin);
4263                         MMPLAYER_FREEIF(mainbin);
4264                 }
4265
4266                 if (tag_list)
4267                         gst_tag_list_unref(tag_list);
4268
4269                 MMPLAYER_FREEIF(player->pipeline);
4270         }
4271         MMPLAYER_FREEIF(player->album_art);
4272
4273         if (player->v_stream_caps) {
4274                 gst_caps_unref(player->v_stream_caps);
4275                 player->v_stream_caps = NULL;
4276         }
4277
4278         if (player->a_stream_caps) {
4279                 gst_caps_unref(player->a_stream_caps);
4280                 player->a_stream_caps = NULL;
4281         }
4282
4283         if (player->s_stream_caps) {
4284                 gst_caps_unref(player->s_stream_caps);
4285                 player->s_stream_caps = NULL;
4286         }
4287         _mmplayer_track_destroy(player);
4288
4289         if (player->sink_elements)
4290                 g_list_free(player->sink_elements);
4291         player->sink_elements = NULL;
4292
4293         if (player->bufmgr) {
4294                 tbm_bufmgr_deinit(player->bufmgr);
4295                 player->bufmgr = NULL;
4296         }
4297
4298         LOGW("finished destroy pipeline");
4299
4300         MMPLAYER_FLEAVE();
4301
4302         return ret;
4303 }
4304
4305 static int
4306 __mmplayer_gst_realize(mmplayer_t *player)
4307 {
4308         gint timeout = 0;
4309         int ret = MM_ERROR_NONE;
4310
4311         MMPLAYER_FENTER();
4312
4313         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4314
4315         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4316
4317         ret = __mmplayer_gst_create_pipeline(player);
4318         if (ret) {
4319                 LOGE("failed to create pipeline");
4320                 return ret;
4321         }
4322
4323         /* set pipeline state to READY */
4324         /* NOTE : state change to READY must be performed sync. */
4325         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4326         ret = _mmplayer_gst_set_state(player,
4327                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4328
4329         if (ret != MM_ERROR_NONE) {
4330                 /* return error if failed to set state */
4331                 LOGE("failed to set READY state");
4332                 return ret;
4333         }
4334
4335         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4336
4337         /* create dot before error-return. for debugging */
4338         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4339
4340         MMPLAYER_FLEAVE();
4341
4342         return ret;
4343 }
4344
4345 static int
4346 __mmplayer_gst_unrealize(mmplayer_t *player)
4347 {
4348         int ret = MM_ERROR_NONE;
4349
4350         MMPLAYER_FENTER();
4351
4352         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4353
4354         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4355         MMPLAYER_PRINT_STATE(player);
4356
4357         /* release miscellaneous information */
4358         __mmplayer_release_misc(player);
4359
4360         /* destroy pipeline */
4361         ret = __mmplayer_gst_destroy_pipeline(player);
4362         if (ret != MM_ERROR_NONE) {
4363                 LOGE("failed to destory pipeline");
4364                 return ret;
4365         }
4366
4367         /* release miscellaneous information.
4368            these info needs to be released after pipeline is destroyed. */
4369         __mmplayer_release_misc_post(player);
4370
4371         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4372
4373         MMPLAYER_FLEAVE();
4374
4375         return ret;
4376 }
4377
4378 static int
4379 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4380 {
4381         MMPLAYER_FENTER();
4382
4383         if (!player) {
4384                 LOGW("set_message_callback is called with invalid player handle");
4385                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4386         }
4387
4388         player->msg_cb = callback;
4389         player->msg_cb_param = user_param;
4390
4391         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4392
4393         MMPLAYER_FLEAVE();
4394
4395         return MM_ERROR_NONE;
4396 }
4397
4398 int
4399 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4400 {
4401         int ret = MM_ERROR_NONE;
4402         char *path = NULL;
4403
4404         MMPLAYER_FENTER();
4405
4406         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4407         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4408         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4409
4410         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4411
4412         if (strstr(uri, "es_buff://")) {
4413                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4414         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4415                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4416         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4417                 gchar *tmp = NULL;
4418                 tmp = g_ascii_strdown(uri, strlen(uri));
4419                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4420                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4421                 else
4422                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4423                 g_free(tmp);
4424         } else if (strstr(uri, "mms://")) {
4425                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4426         } else if ((path = strstr(uri, "mem://"))) {
4427                 ret = __mmplayer_set_mem_uri(data, path, param);
4428         } else {
4429                 ret = __mmplayer_set_file_uri(data, uri);
4430         }
4431
4432         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4433                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4434         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4435                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4436
4437         /* dump parse result */
4438         SECURE_LOGW("incoming uri : %s", uri);
4439         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4440                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4441
4442         MMPLAYER_FLEAVE();
4443
4444         return ret;
4445 }
4446
4447 static gboolean
4448 __mmplayer_can_do_interrupt(mmplayer_t *player)
4449 {
4450         if (!player || !player->pipeline || !player->attrs) {
4451                 LOGW("not initialized");
4452                 goto FAILED;
4453         }
4454
4455         if (player->audio_decoded_cb) {
4456                 LOGW("not support in pcm extraction mode");
4457                 goto FAILED;
4458         }
4459
4460         /* check if seeking */
4461         if (player->seek_state != MMPLAYER_SEEK_NONE) {
4462                 MMMessageParamType msg_param;
4463                 memset(&msg_param, 0, sizeof(MMMessageParamType));
4464                 msg_param.code = MM_ERROR_PLAYER_SEEK;
4465                 player->seek_state = MMPLAYER_SEEK_NONE;
4466                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4467                 goto FAILED;
4468         }
4469
4470         /* check other thread */
4471         if (!MMPLAYER_CMD_TRYLOCK(player)) {
4472                 LOGW("locked already, cmd state : %d", player->cmd);
4473
4474                 /* check application command */
4475                 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4476                         LOGW("playing.. should wait cmd lock then, will be interrupted");
4477
4478                         /* lock will be released at mrp_resource_release_cb() */
4479                         MMPLAYER_CMD_LOCK(player);
4480                         goto INTERRUPT;
4481                 }
4482                 LOGW("nothing to do");
4483                 goto FAILED;
4484         } else {
4485                 LOGW("can interrupt immediately");
4486                 goto INTERRUPT;
4487         }
4488
4489 FAILED:    /* with CMD UNLOCKED */
4490         return FALSE;
4491
4492 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4493         return TRUE;
4494 }
4495
4496 static int
4497 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4498                 void *user_data)
4499 {
4500         mmplayer_t *player = NULL;
4501         MMMessageParamType msg = {0, };
4502         gint64 pos = 0;
4503         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4504
4505         MMPLAYER_FENTER();
4506
4507         if (!user_data) {
4508                 LOGE("user_data is null");
4509                 return FALSE;
4510         }
4511         player = (mmplayer_t *)user_data;
4512
4513         if (!__mmplayer_can_do_interrupt(player)) {
4514                 LOGW("no need to interrupt, so leave");
4515                 /* FIXME: there is no way to avoid releasing resource. */
4516                 return FALSE;
4517         }
4518
4519         player->interrupted_by_resource = TRUE;
4520
4521         /* get last play position */
4522         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4523                 msg.union_type = MM_MSG_UNION_TIME;
4524                 msg.time.elapsed = pos;
4525                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4526         } else {
4527                 LOGW("failed to get play position.");
4528         }
4529
4530         LOGD("video resource conflict so, resource will be freed by unrealizing");
4531         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4532                 LOGE("failed to unrealize");
4533
4534         /* lock is called in __mmplayer_can_do_interrupt() */
4535         MMPLAYER_CMD_UNLOCK(player);
4536
4537         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4538                 player->hw_resource[res_idx] = NULL;
4539         }
4540
4541         MMPLAYER_FLEAVE();
4542         return TRUE; /* release all the resources */
4543 }
4544
4545 static void
4546 __mmplayer_initialize_video_roi(mmplayer_t *player)
4547 {
4548         player->video_roi.scale_x = 0.0;
4549         player->video_roi.scale_y = 0.0;
4550         player->video_roi.scale_width = 1.0;
4551         player->video_roi.scale_height = 1.0;
4552 }
4553
4554 int
4555 _mmplayer_create_player(MMHandleType handle)
4556 {
4557         int ret = MM_ERROR_PLAYER_INTERNAL;
4558         bool enabled = false;
4559
4560         mmplayer_t *player = MM_PLAYER_CAST(handle);
4561
4562         MMPLAYER_FENTER();
4563
4564         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4565
4566         /* initialize player state */
4567         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4568         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4569         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4570         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4571
4572         /* check current state */
4573         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4574
4575         /* construct attributes */
4576         player->attrs = _mmplayer_construct_attribute(handle);
4577
4578         if (!player->attrs) {
4579                 LOGE("Failed to construct attributes");
4580                 return ret;
4581         }
4582
4583         /* initialize gstreamer with configured parameter */
4584         if (!__mmplayer_init_gstreamer(player)) {
4585                 LOGE("Initializing gstreamer failed");
4586                 _mmplayer_deconstruct_attribute(handle);
4587                 return ret;
4588         }
4589
4590         /* create lock. note that g_tread_init() has already called in gst_init() */
4591         g_mutex_init(&player->fsink_lock);
4592
4593         /* create update tag lock */
4594         g_mutex_init(&player->update_tag_lock);
4595
4596         /* create gapless play mutex */
4597         g_mutex_init(&player->gapless_play_thread_mutex);
4598
4599         /* create gapless play cond */
4600         g_cond_init(&player->gapless_play_thread_cond);
4601
4602         /* create gapless play thread */
4603         player->gapless_play_thread =
4604                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4605         if (!player->gapless_play_thread) {
4606                 LOGE("failed to create gapless play thread");
4607                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4608                 g_mutex_clear(&player->gapless_play_thread_mutex);
4609                 g_cond_clear(&player->gapless_play_thread_cond);
4610                 goto ERROR;
4611         }
4612
4613         player->bus_msg_q = g_queue_new();
4614         if (!player->bus_msg_q) {
4615                 LOGE("failed to create queue for bus_msg");
4616                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4617                 goto ERROR;
4618         }
4619
4620         ret = _mmplayer_initialize_video_capture(player);
4621         if (ret != MM_ERROR_NONE) {
4622                 LOGE("failed to initialize video capture");
4623                 goto ERROR;
4624         }
4625
4626         /* initialize resource manager */
4627         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4628                 __resource_release_cb, player, &player->resource_manager)
4629                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4630                 LOGE("failed to initialize resource manager");
4631                 ret = MM_ERROR_PLAYER_INTERNAL;
4632                 goto ERROR;
4633         }
4634
4635         /* create video bo lock and cond */
4636         g_mutex_init(&player->video_bo_mutex);
4637         g_cond_init(&player->video_bo_cond);
4638
4639         /* create subtitle info lock and cond */
4640         g_mutex_init(&player->subtitle_info_mutex);
4641         g_cond_init(&player->subtitle_info_cond);
4642
4643         player->streaming_type = STREAMING_SERVICE_NONE;
4644
4645         /* give default value of audio effect setting */
4646         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4647         player->sound.rg_enable = false;
4648         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4649
4650         player->play_subtitle = FALSE;
4651         player->has_closed_caption = FALSE;
4652         player->pending_resume = FALSE;
4653         if (player->ini.dump_element_keyword[0][0] == '\0')
4654                 player->ini.set_dump_element_flag = FALSE;
4655         else
4656                 player->ini.set_dump_element_flag = TRUE;
4657
4658         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4659         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4660         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4661
4662         /* Set video360 settings to their defaults for just-created player.
4663          * */
4664
4665         player->is_360_feature_enabled = FALSE;
4666         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4667                 LOGI("spherical feature info: %d", enabled);
4668                 if (enabled)
4669                         player->is_360_feature_enabled = TRUE;
4670         } else {
4671                 LOGE("failed to get spherical feature info");
4672         }
4673
4674         player->is_content_spherical = FALSE;
4675         player->is_video360_enabled = TRUE;
4676         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4677         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4678         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4679         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4680         player->video360_zoom = 1.0f;
4681         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4682         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4683
4684         __mmplayer_initialize_video_roi(player);
4685
4686         /* set player state to null */
4687         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4688         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4689
4690         MMPLAYER_FLEAVE();
4691
4692         return MM_ERROR_NONE;
4693
4694 ERROR:
4695         /* free lock */
4696         g_mutex_clear(&player->fsink_lock);
4697         /* free update tag lock */
4698         g_mutex_clear(&player->update_tag_lock);
4699         g_queue_free(player->bus_msg_q);
4700         player->bus_msg_q = NULL;
4701         /* free gapless play thread */
4702         if (player->gapless_play_thread) {
4703                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4704                 player->gapless_play_thread_exit = TRUE;
4705                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4706                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4707
4708                 g_thread_join(player->gapless_play_thread);
4709                 player->gapless_play_thread = NULL;
4710
4711                 g_mutex_clear(&player->gapless_play_thread_mutex);
4712                 g_cond_clear(&player->gapless_play_thread_cond);
4713         }
4714
4715         /* release attributes */
4716         _mmplayer_deconstruct_attribute(handle);
4717
4718         MMPLAYER_FLEAVE();
4719
4720         return ret;
4721 }
4722
4723 static gboolean
4724 __mmplayer_init_gstreamer(mmplayer_t *player)
4725 {
4726         static gboolean initialized = FALSE;
4727         static const int max_argc = 50;
4728         gint *argc = NULL;
4729         gchar **argv = NULL;
4730         gchar **argv2 = NULL;
4731         GError *err = NULL;
4732         int i = 0;
4733         int arg_count = 0;
4734
4735         if (initialized) {
4736                 LOGD("gstreamer already initialized.");
4737                 return TRUE;
4738         }
4739
4740         /* alloc */
4741         argc = malloc(sizeof(int));
4742         argv = malloc(sizeof(gchar *) * max_argc);
4743         argv2 = malloc(sizeof(gchar *) * max_argc);
4744
4745         if (!argc || !argv || !argv2)
4746                 goto ERROR;
4747
4748         memset(argv, 0, sizeof(gchar *) * max_argc);
4749         memset(argv2, 0, sizeof(gchar *) * max_argc);
4750
4751         /* add initial */
4752         *argc = 1;
4753         argv[0] = g_strdup("mmplayer");
4754
4755         /* add gst_param */
4756         for (i = 0; i < 5; i++) {
4757                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4758                 if (strlen(player->ini.gst_param[i]) > 0) {
4759                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4760                         (*argc)++;
4761                 }
4762         }
4763
4764         /* we would not do fork for scanning plugins */
4765         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4766         (*argc)++;
4767
4768         /* check disable registry scan */
4769         if (player->ini.skip_rescan) {
4770                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4771                 (*argc)++;
4772         }
4773
4774         /* check disable segtrap */
4775         if (player->ini.disable_segtrap) {
4776                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4777                 (*argc)++;
4778         }
4779
4780         LOGD("initializing gstreamer with following parameter");
4781         LOGD("argc : %d", *argc);
4782         arg_count = *argc;
4783
4784         for (i = 0; i < arg_count; i++) {
4785                 argv2[i] = argv[i];
4786                 LOGD("argv[%d] : %s", i, argv2[i]);
4787         }
4788
4789         /* initializing gstreamer */
4790         if (!gst_init_check(argc, &argv, &err)) {
4791                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4792                 if (err)
4793                         g_error_free(err);
4794
4795                 goto ERROR;
4796         }
4797         /* release */
4798         for (i = 0; i < arg_count; i++) {
4799 #ifdef __DEBUG__
4800                 LOGD("release - argv[%d] : %s", i, argv2[i]);
4801 #endif
4802                 MMPLAYER_FREEIF(argv2[i]);
4803         }
4804
4805         MMPLAYER_FREEIF(argv);
4806         MMPLAYER_FREEIF(argv2);
4807         MMPLAYER_FREEIF(argc);
4808
4809         /* done */
4810         initialized = TRUE;
4811
4812         return TRUE;
4813
4814 ERROR:
4815
4816         /* release */
4817         for (i = 0; i < arg_count; i++) {
4818                 LOGD("free[%d] : %s", i, argv2[i]);
4819                 MMPLAYER_FREEIF(argv2[i]);
4820         }
4821
4822         MMPLAYER_FREEIF(argv);
4823         MMPLAYER_FREEIF(argv2);
4824         MMPLAYER_FREEIF(argc);
4825
4826         return FALSE;
4827 }
4828
4829 static void
4830 __mmplayer_check_async_state_transition(mmplayer_t *player)
4831 {
4832         GstState element_state = GST_STATE_VOID_PENDING;
4833         GstState element_pending_state = GST_STATE_VOID_PENDING;
4834         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4835         GstElement *element = NULL;
4836         gboolean async = FALSE;
4837
4838         /* check player handle */
4839         MMPLAYER_RETURN_IF_FAIL(player &&
4840                                                 player->pipeline &&
4841                                                 player->pipeline->mainbin &&
4842                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4843
4844         if (player->attrs)
4845                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4846
4847         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4848                 LOGD("don't need to check the pipeline state");
4849                 return;
4850         }
4851
4852         MMPLAYER_PRINT_STATE(player);
4853
4854         /* wait for state transition */
4855         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4856         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4857
4858         if (ret == GST_STATE_CHANGE_FAILURE) {
4859                 LOGE(" [%s] state : %s   pending : %s",
4860                         GST_ELEMENT_NAME(element),
4861                         gst_element_state_get_name(element_state),
4862                         gst_element_state_get_name(element_pending_state));
4863
4864                 /* dump state of all element */
4865                 _mmplayer_dump_pipeline_state(player);
4866
4867                 return;
4868         }
4869
4870         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4871         return;
4872 }
4873
4874 int
4875 _mmplayer_destroy(MMHandleType handle)
4876 {
4877         mmplayer_t *player = MM_PLAYER_CAST(handle);
4878
4879         MMPLAYER_FENTER();
4880
4881         /* check player handle */
4882         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4883
4884         /* destroy can called at anytime */
4885         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4886
4887         /* check async state transition */
4888         __mmplayer_check_async_state_transition(player);
4889
4890         /* release gapless play thread */
4891         if (player->gapless_play_thread) {
4892                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4893                 player->gapless_play_thread_exit = TRUE;
4894                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4895                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4896
4897                 LOGD("waitting for gapless play thread exit");
4898                 g_thread_join(player->gapless_play_thread);
4899                 g_mutex_clear(&player->gapless_play_thread_mutex);
4900                 g_cond_clear(&player->gapless_play_thread_cond);
4901                 LOGD("gapless play thread released");
4902         }
4903
4904         _mmplayer_release_video_capture(player);
4905
4906         /* de-initialize resource manager */
4907         if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4908                         player->resource_manager))
4909                 LOGE("failed to deinitialize resource manager");
4910
4911         /* release pipeline */
4912         if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4913                 LOGE("failed to destory pipeline");
4914                 return MM_ERROR_PLAYER_INTERNAL;
4915         }
4916
4917         g_queue_free(player->bus_msg_q);
4918
4919         /* release subtitle info lock and cond */
4920         g_mutex_clear(&player->subtitle_info_mutex);
4921         g_cond_clear(&player->subtitle_info_cond);
4922
4923         __mmplayer_release_dump_list(player->dump_list);
4924
4925         /* release miscellaneous information */
4926         __mmplayer_release_misc(player);
4927
4928         /* release miscellaneous information.
4929            these info needs to be released after pipeline is destroyed. */
4930         __mmplayer_release_misc_post(player);
4931
4932         /* release attributes */
4933         _mmplayer_deconstruct_attribute(handle);
4934
4935         /* release lock */
4936         g_mutex_clear(&player->fsink_lock);
4937
4938         /* release lock */
4939         g_mutex_clear(&player->update_tag_lock);
4940
4941         /* release video bo lock and cond */
4942         g_mutex_clear(&player->video_bo_mutex);
4943         g_cond_clear(&player->video_bo_cond);
4944
4945         MMPLAYER_FLEAVE();
4946
4947         return MM_ERROR_NONE;
4948 }
4949
4950 int
4951 _mmplayer_realize(MMHandleType hplayer)
4952 {
4953         mmplayer_t *player = (mmplayer_t *)hplayer;
4954         char *uri = NULL;
4955         void *param = NULL;
4956         MMHandleType attrs = 0;
4957         int ret = MM_ERROR_NONE;
4958
4959         MMPLAYER_FENTER();
4960
4961         /* check player handle */
4962         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4963
4964         /* check current state */
4965         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4966
4967         attrs = MMPLAYER_GET_ATTRS(player);
4968         if (!attrs) {
4969                 LOGE("fail to get attributes.");
4970                 return MM_ERROR_PLAYER_INTERNAL;
4971         }
4972         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4973         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
4974
4975         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4976                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4977
4978                 if (ret != MM_ERROR_NONE) {
4979                         LOGE("failed to parse profile");
4980                         return ret;
4981                 }
4982         }
4983
4984         if (uri && (strstr(uri, "es_buff://"))) {
4985                 if (strstr(uri, "es_buff://push_mode"))
4986                         player->es_player_push_mode = TRUE;
4987                 else
4988                         player->es_player_push_mode = FALSE;
4989         }
4990
4991         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4992                 LOGW("mms protocol is not supported format.");
4993                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4994         }
4995
4996         if (MMPLAYER_IS_STREAMING(player))
4997                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4998         else
4999                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5000
5001         player->smooth_streaming = FALSE;
5002         player->videodec_linked  = 0;
5003         player->audiodec_linked  = 0;
5004         player->textsink_linked = 0;
5005         player->is_external_subtitle_present = FALSE;
5006         player->is_external_subtitle_added_now = FALSE;
5007         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5008         player->video360_metadata.is_spherical = -1;
5009         player->is_openal_plugin_used = FALSE;
5010         player->demux_pad_index = 0;
5011         player->subtitle_language_list = NULL;
5012         player->is_subtitle_force_drop = FALSE;
5013
5014         _mmplayer_track_initialize(player);
5015         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5016
5017         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5018                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5019
5020                 player->streamer = _mm_player_streaming_create();
5021                 _mm_player_streaming_initialize(player->streamer, TRUE);
5022
5023                 mm_attrs_multiple_get(player->attrs, NULL,
5024                                 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5025                                 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5026
5027                 if (prebuffer_ms > 0) {
5028                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5029                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5030                 }
5031
5032                 if (rebuffer_ms > 0) {
5033                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5034                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5035                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5036                 }
5037
5038                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5039                                                                 player->streamer->buffering_req.rebuffer_time);
5040         }
5041
5042         /* realize pipeline */
5043         ret = __mmplayer_gst_realize(player);
5044         if (ret != MM_ERROR_NONE)
5045                 LOGE("fail to realize the player.");
5046
5047         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5048
5049         MMPLAYER_FLEAVE();
5050
5051         return ret;
5052 }
5053
5054 int
5055 _mmplayer_unrealize(MMHandleType hplayer)
5056 {
5057         mmplayer_t *player = (mmplayer_t *)hplayer;
5058         int ret = MM_ERROR_NONE;
5059
5060         MMPLAYER_FENTER();
5061
5062         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5063
5064         MMPLAYER_CMD_UNLOCK(player);
5065         /* destroy the gst bus msg thread which is created during realize.
5066            this funct have to be called before getting cmd lock. */
5067         _mmplayer_bus_msg_thread_destroy(player);
5068         MMPLAYER_CMD_LOCK(player);
5069
5070         /* check current state */
5071         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5072
5073         /* check async state transition */
5074         __mmplayer_check_async_state_transition(player);
5075
5076         /* unrealize pipeline */
5077         ret = __mmplayer_gst_unrealize(player);
5078
5079         if (!player->interrupted_by_resource) {
5080                 int rm_ret = MM_ERROR_NONE;
5081                 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5082
5083                 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5084                         rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5085                         if (rm_ret != MM_ERROR_NONE)
5086                                 LOGE("failed to release [%d] resources", res_idx);
5087                 }
5088         }
5089
5090         MMPLAYER_FLEAVE();
5091         return ret;
5092 }
5093
5094 int
5095 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5096 {
5097         mmplayer_t *player = (mmplayer_t *)hplayer;
5098
5099         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5100
5101         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5102 }
5103
5104 int
5105 _mmplayer_get_state(MMHandleType hplayer, int *state)
5106 {
5107         mmplayer_t *player = (mmplayer_t *)hplayer;
5108
5109         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5110
5111         *state = MMPLAYER_CURRENT_STATE(player);
5112
5113         return MM_ERROR_NONE;
5114 }
5115
5116 static int
5117 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5118 {
5119         GstElement *vol_element = NULL;
5120         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5121
5122         MMPLAYER_FENTER();
5123         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5124         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5125
5126         /* check pipeline handle */
5127         if (!player->pipeline || !player->pipeline->audiobin) {
5128                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5129
5130                 /* NOTE : stored value will be used in create_audiobin
5131                  * returning MM_ERROR_NONE here makes application to able to
5132                  * set audio volume or mute at anytime.
5133                  */
5134                 return MM_ERROR_NONE;
5135         }
5136
5137         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5138                 volume_elem_id = MMPLAYER_A_SINK;
5139
5140         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5141         if (!vol_element) {
5142                 LOGE("failed to get vol element %d", volume_elem_id);
5143                 return MM_ERROR_PLAYER_INTERNAL;
5144         }
5145
5146         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5147
5148         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5149                 LOGE("there is no '%s' property", prop_name);
5150                 return MM_ERROR_PLAYER_INTERNAL;
5151         }
5152
5153         if (!strcmp(prop_name, "volume")) {
5154                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5155         } else if (!strcmp(prop_name, "mute")) {
5156                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5157         } else {
5158                 LOGE("invalid property %s", prop_name);
5159                 return MM_ERROR_PLAYER_INTERNAL;
5160         }
5161
5162         return MM_ERROR_NONE;
5163 }
5164
5165 int
5166 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5167 {
5168         int ret = MM_ERROR_NONE;
5169         mmplayer_t *player = (mmplayer_t *)hplayer;
5170
5171         MMPLAYER_FENTER();
5172         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5173
5174         LOGD("volume = %f", volume);
5175
5176         /* invalid factor range or not */
5177         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5178                 LOGE("Invalid volume value");
5179                 return MM_ERROR_INVALID_ARGUMENT;
5180         }
5181
5182         player->sound.volume = volume;
5183
5184         ret = __mmplayer_gst_set_volume_property(player, "volume");
5185
5186         MMPLAYER_FLEAVE();
5187         return ret;
5188 }
5189
5190 int
5191 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5192 {
5193         mmplayer_t *player = (mmplayer_t *)hplayer;
5194
5195         MMPLAYER_FENTER();
5196
5197         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5198         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5199
5200         *volume = player->sound.volume;
5201
5202         LOGD("current vol = %f", *volume);
5203
5204         MMPLAYER_FLEAVE();
5205         return MM_ERROR_NONE;
5206 }
5207
5208 int
5209 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5210 {
5211         int ret = MM_ERROR_NONE;
5212         mmplayer_t *player = (mmplayer_t *)hplayer;
5213
5214         MMPLAYER_FENTER();
5215         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5216
5217         LOGD("mute = %d", mute);
5218
5219         player->sound.mute = mute;
5220
5221         ret = __mmplayer_gst_set_volume_property(player, "mute");
5222
5223         MMPLAYER_FLEAVE();
5224         return ret;
5225 }
5226
5227 int
5228 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5229 {
5230         mmplayer_t *player = (mmplayer_t *)hplayer;
5231
5232         MMPLAYER_FENTER();
5233
5234         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5236
5237         *mute = player->sound.mute;
5238
5239         LOGD("current mute = %d", *mute);
5240
5241         MMPLAYER_FLEAVE();
5242
5243         return MM_ERROR_NONE;
5244 }
5245
5246 int
5247 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5248 {
5249         mmplayer_t *player = (mmplayer_t *)hplayer;
5250
5251         MMPLAYER_FENTER();
5252
5253         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5254
5255         player->audio_stream_changed_cb = callback;
5256         player->audio_stream_changed_cb_user_param = user_param;
5257         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5258
5259         MMPLAYER_FLEAVE();
5260
5261         return MM_ERROR_NONE;
5262 }
5263
5264 int
5265 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5266 {
5267         mmplayer_t *player = (mmplayer_t *)hplayer;
5268
5269         MMPLAYER_FENTER();
5270
5271         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5272
5273         player->audio_decoded_cb = callback;
5274         player->audio_decoded_cb_user_param = user_param;
5275         player->audio_extract_opt = opt;
5276         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5277
5278         MMPLAYER_FLEAVE();
5279
5280         return MM_ERROR_NONE;
5281 }
5282
5283 int
5284 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5285 {
5286         mmplayer_t *player = (mmplayer_t *)hplayer;
5287
5288         MMPLAYER_FENTER();
5289
5290         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5291
5292         if (callback && !player->bufmgr)
5293                 player->bufmgr = tbm_bufmgr_init(-1);
5294
5295         player->set_mode.video_export = (callback) ? true : false;
5296         player->video_decoded_cb = callback;
5297         player->video_decoded_cb_user_param = user_param;
5298
5299         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5300
5301         MMPLAYER_FLEAVE();
5302
5303         return MM_ERROR_NONE;
5304 }
5305
5306 int
5307 _mmplayer_start(MMHandleType hplayer)
5308 {
5309         mmplayer_t *player = (mmplayer_t *)hplayer;
5310         gint ret = MM_ERROR_NONE;
5311
5312         MMPLAYER_FENTER();
5313
5314         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5315
5316         /* check current state */
5317         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5318
5319         /* start pipeline */
5320         ret = _mmplayer_gst_start(player);
5321         if (ret != MM_ERROR_NONE)
5322                 LOGE("failed to start player.");
5323
5324         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5325                 LOGD("force playing start even during buffering");
5326                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5327         }
5328
5329         MMPLAYER_FLEAVE();
5330
5331         return ret;
5332 }
5333
5334 /* NOTE: post "not supported codec message" to application
5335  * when one codec is not found during AUTOPLUGGING in MSL.
5336  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5337  * And, if any codec is not found, don't send message here.
5338  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5339  */
5340 int
5341 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5342 {
5343         MMMessageParamType msg_param;
5344         memset(&msg_param, 0, sizeof(MMMessageParamType));
5345         gboolean post_msg_direct = FALSE;
5346
5347         MMPLAYER_FENTER();
5348
5349         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5350
5351         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5352                         player->not_supported_codec, player->can_support_codec);
5353
5354         if (player->not_found_demuxer) {
5355                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5356                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5357
5358                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5359                 MMPLAYER_FREEIF(msg_param.data);
5360
5361                 return MM_ERROR_NONE;
5362         }
5363
5364         if (player->not_supported_codec) {
5365                 if (player->can_support_codec) {
5366                         // There is one codec to play
5367                         post_msg_direct = TRUE;
5368                 } else {
5369                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5370                                 post_msg_direct = TRUE;
5371                 }
5372
5373                 if (post_msg_direct) {
5374                         MMMessageParamType msg_param;
5375                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5376
5377                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5378                                 LOGW("not found AUDIO codec, posting error code to application.");
5379
5380                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5381                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5382                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5383                                 LOGW("not found VIDEO codec, posting error code to application.");
5384
5385                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5386                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5387                         }
5388
5389                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5390
5391                         MMPLAYER_FREEIF(msg_param.data);
5392
5393                         return MM_ERROR_NONE;
5394                 } else {
5395                         // no any supported codec case
5396                         LOGW("not found any codec, posting error code to application.");
5397
5398                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5399                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5400                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5401                         } else {
5402                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5403                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5404                         }
5405
5406                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5407
5408                         MMPLAYER_FREEIF(msg_param.data);
5409                 }
5410         }
5411
5412         MMPLAYER_FLEAVE();
5413
5414         return MM_ERROR_NONE;
5415 }
5416
5417 static void
5418 __mmplayer_check_pipeline(mmplayer_t *player)
5419 {
5420         GstState element_state = GST_STATE_VOID_PENDING;
5421         GstState element_pending_state = GST_STATE_VOID_PENDING;
5422         gint timeout = 0;
5423         int ret = MM_ERROR_NONE;
5424
5425         if (!player->gapless.reconfigure)
5426                 return;
5427
5428         LOGW("pipeline is under construction.");
5429
5430         MMPLAYER_PLAYBACK_LOCK(player);
5431         MMPLAYER_PLAYBACK_UNLOCK(player);
5432
5433         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5434
5435         /* wait for state transition */
5436         ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5437         if (ret == GST_STATE_CHANGE_FAILURE)
5438                 LOGE("failed to change pipeline state within %d sec", timeout);
5439 }
5440
5441 /* NOTE : it should be able to call 'stop' anytime*/
5442 int
5443 _mmplayer_stop(MMHandleType hplayer)
5444 {
5445         mmplayer_t *player = (mmplayer_t *)hplayer;
5446         int ret = MM_ERROR_NONE;
5447
5448         MMPLAYER_FENTER();
5449
5450         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5451
5452         /* check current state */
5453         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5454
5455         /* check pipline building state */
5456         __mmplayer_check_pipeline(player);
5457         __mmplayer_reset_gapless_state(player);
5458
5459         /* NOTE : application should not wait for EOS after calling STOP */
5460         _mmplayer_cancel_eos_timer(player);
5461
5462         /* reset */
5463         player->seek_state = MMPLAYER_SEEK_NONE;
5464
5465         /* stop pipeline */
5466         ret = _mmplayer_gst_stop(player);
5467
5468         if (ret != MM_ERROR_NONE)
5469                 LOGE("failed to stop player.");
5470
5471         MMPLAYER_FLEAVE();
5472
5473         return ret;
5474 }
5475
5476 int
5477 _mmplayer_pause(MMHandleType hplayer)
5478 {
5479         mmplayer_t *player = (mmplayer_t *)hplayer;
5480         gint64 pos_nsec = 0;
5481         gboolean async = FALSE;
5482         gint ret = MM_ERROR_NONE;
5483
5484         MMPLAYER_FENTER();
5485
5486         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5487
5488         /* check current state */
5489         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5490
5491         /* check pipline building state */
5492         __mmplayer_check_pipeline(player);
5493
5494         switch (MMPLAYER_CURRENT_STATE(player)) {
5495         case MM_PLAYER_STATE_READY:
5496                 {
5497                         /* check prepare async or not.
5498                          * In the case of streaming playback, it's recommned to avoid blocking wait.
5499                          */
5500                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5501                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5502
5503                         /* Changing back sync of rtspsrc to async */
5504                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5505                                 LOGD("async prepare working mode for rtsp");
5506                                 async = TRUE;
5507                         }
5508                 }
5509                 break;
5510
5511         case MM_PLAYER_STATE_PLAYING:
5512                 {
5513                         /* NOTE : store current point to overcome some bad operation
5514                         *(returning zero when getting current position in paused state) of some
5515                         * elements
5516                         */
5517                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5518                                 LOGW("getting current position failed in paused");
5519
5520                         player->last_position = pos_nsec;
5521
5522                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5523                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5524                            This causes problem is position calculation during normal pause resume scenarios also.
5525                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5526                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5527                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5528                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5529                         }
5530                 }
5531                 break;
5532         }
5533
5534         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5535                 LOGD("doing async pause in case of ms buff src");
5536                 async = TRUE;
5537         }
5538
5539         /* pause pipeline */
5540         ret = _mmplayer_gst_pause(player, async);
5541
5542         if (ret != MM_ERROR_NONE)
5543                 LOGE("failed to pause player. ret : 0x%x", ret);
5544
5545         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5546                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5547                         LOGE("failed to update display_rotation");
5548         }
5549
5550         MMPLAYER_FLEAVE();
5551
5552         return ret;
5553 }
5554
5555 /* in case of streaming, pause could take long time.*/
5556 int
5557 _mmplayer_abort_pause(MMHandleType hplayer)
5558 {
5559         mmplayer_t *player = (mmplayer_t *)hplayer;
5560         int ret = MM_ERROR_NONE;
5561
5562         MMPLAYER_FENTER();
5563
5564         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5565                                                 player->pipeline &&
5566                                                 player->pipeline->mainbin,
5567                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5568
5569         LOGD("set the pipeline state to READY");
5570
5571         /* set state to READY */
5572         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5573                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5574         if (ret != MM_ERROR_NONE) {
5575                 LOGE("fail to change state to READY");
5576                 return MM_ERROR_PLAYER_INTERNAL;
5577         }
5578
5579         LOGD("succeeded in changing state to READY");
5580         return ret;
5581 }
5582
5583 int
5584 _mmplayer_resume(MMHandleType hplayer)
5585 {
5586         mmplayer_t *player = (mmplayer_t *)hplayer;
5587         int ret = MM_ERROR_NONE;
5588         gboolean async = FALSE;
5589
5590         MMPLAYER_FENTER();
5591
5592         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5593
5594         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5595                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5596                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5597                         return ret;
5598                 }
5599
5600                 /* Changing back sync mode rtspsrc to async */
5601                 LOGD("async resume for rtsp case");
5602                 async = TRUE;
5603         }
5604
5605         /* check current state */
5606         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5607
5608         ret = _mmplayer_gst_resume(player, async);
5609         if (ret != MM_ERROR_NONE)
5610                 LOGE("failed to resume player.");
5611
5612         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5613                 LOGD("force resume even during buffering");
5614                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5615         }
5616
5617         MMPLAYER_FLEAVE();
5618
5619         return ret;
5620 }
5621
5622 int
5623 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5624 {
5625         mmplayer_t *player = (mmplayer_t *)hplayer;
5626         gint64 pos_nsec = 0;
5627         int ret = MM_ERROR_NONE;
5628         bool mute = false;
5629         signed long long start = 0, stop = 0;
5630         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5631         MMPLAYER_FENTER();
5632
5633         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5634         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5635
5636         /* The sound of video is not supported under 0.0 and over 2.0. */
5637         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5638                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5639                         mute = true;
5640         }
5641         _mmplayer_set_mute(hplayer, mute);
5642
5643         if (player->playback_rate == rate)
5644                 return MM_ERROR_NONE;
5645
5646         /* If the position is reached at start potion during fast backward, EOS is posted.
5647          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5648          */
5649         player->playback_rate = rate;
5650
5651         current_state = MMPLAYER_CURRENT_STATE(player);
5652
5653         if (current_state != MM_PLAYER_STATE_PAUSED)
5654                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5655
5656         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5657
5658         if ((current_state == MM_PLAYER_STATE_PAUSED)
5659                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5660                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5661                 pos_nsec = player->last_position;
5662         }
5663
5664         if (rate >= 0) {
5665                 start = pos_nsec;
5666                 stop = GST_CLOCK_TIME_NONE;
5667         } else {
5668                 start = GST_CLOCK_TIME_NONE;
5669                 stop = pos_nsec;
5670         }
5671
5672         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5673                                 player->playback_rate,
5674                                 GST_FORMAT_TIME,
5675                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5676                                 GST_SEEK_TYPE_SET, start,
5677                                 GST_SEEK_TYPE_SET, stop)) {
5678                 LOGE("failed to set speed playback");
5679                 return MM_ERROR_PLAYER_SEEK;
5680         }
5681
5682         LOGD("succeeded to set speed playback as %0.1f", rate);
5683
5684         MMPLAYER_FLEAVE();
5685
5686         return MM_ERROR_NONE;;
5687 }
5688
5689 int
5690 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5691 {
5692         mmplayer_t *player = (mmplayer_t *)hplayer;
5693         int ret = MM_ERROR_NONE;
5694
5695         MMPLAYER_FENTER();
5696
5697         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5698
5699         /* check pipline building state */
5700         __mmplayer_check_pipeline(player);
5701
5702         ret = _mmplayer_gst_set_position(player, position, FALSE);
5703
5704         MMPLAYER_FLEAVE();
5705
5706         return ret;
5707 }
5708
5709 int
5710 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5711 {
5712         mmplayer_t *player = (mmplayer_t *)hplayer;
5713         int ret = MM_ERROR_NONE;
5714
5715         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5717
5718         if (g_strrstr(player->type, "video/mpegts"))
5719                 __mmplayer_update_duration_value(player);
5720
5721         *duration = player->duration;
5722         return ret;
5723 }
5724
5725 int
5726 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5727 {
5728         mmplayer_t *player = (mmplayer_t *)hplayer;
5729         int ret = MM_ERROR_NONE;
5730
5731         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5732
5733         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5734
5735         return ret;
5736 }
5737
5738 int
5739 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5740 {
5741         mmplayer_t *player = (mmplayer_t *)hplayer;
5742         int ret = MM_ERROR_NONE;
5743
5744         MMPLAYER_FENTER();
5745
5746         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5747
5748         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5749
5750         MMPLAYER_FLEAVE();
5751
5752         return ret;
5753 }
5754
5755 static gboolean
5756 __mmplayer_is_midi_type(gchar *str_caps)
5757 {
5758         if ((g_strrstr(str_caps, "audio/midi")) ||
5759                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5760                 (g_strrstr(str_caps, "application/x-smaf")) ||
5761                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5762                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5763                 (g_strrstr(str_caps, "audio/xmf")) ||
5764                 (g_strrstr(str_caps, "audio/mxmf"))) {
5765                 LOGD("midi");
5766                 return TRUE;
5767         }
5768
5769         return FALSE;
5770 }
5771
5772 static gboolean
5773 __mmplayer_is_only_mp3_type(gchar *str_caps)
5774 {
5775         if (g_strrstr(str_caps, "application/x-id3") ||
5776                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5777                 return TRUE;
5778         return FALSE;
5779 }
5780
5781 static void
5782 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5783 {
5784         GstStructure *caps_structure = NULL;
5785         gint samplerate = 0;
5786         gint channels = 0;
5787
5788         MMPLAYER_FENTER();
5789         MMPLAYER_RETURN_IF_FAIL(player && caps);
5790
5791         caps_structure = gst_caps_get_structure(caps, 0);
5792
5793         /* set stream information */
5794         gst_structure_get_int(caps_structure, "rate", &samplerate);
5795         gst_structure_get_int(caps_structure, "channels", &channels);
5796
5797         mm_player_set_attribute((MMHandleType)player, NULL,
5798                         "content_audio_samplerate", samplerate,
5799                         "content_audio_channels", channels, NULL);
5800
5801         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5802 }
5803
5804 static void
5805 __mmplayer_update_content_type_info(mmplayer_t *player)
5806 {
5807         MMPLAYER_FENTER();
5808         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5809
5810         if (__mmplayer_is_midi_type(player->type)) {
5811                 player->bypass_audio_effect = TRUE;
5812                 return;
5813         }
5814
5815         if (!player->streamer) {
5816                 LOGD("no need to check streaming type");
5817                 return;
5818         }
5819
5820         if (g_strrstr(player->type, "application/x-hls")) {
5821                 /* If it can't know exact type when it parses uri because of redirection case,
5822                  * it will be fixed by typefinder or when doing autoplugging.
5823                  */
5824                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5825                 player->streamer->is_adaptive_streaming = TRUE;
5826         } else if (g_strrstr(player->type, "application/dash+xml")) {
5827                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5828                 player->streamer->is_adaptive_streaming = TRUE;
5829         }
5830
5831         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5832         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5833                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5834
5835                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5836                         if (player->streamer->is_adaptive_streaming)
5837                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5838                         else
5839                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5840                 }
5841         }
5842
5843         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5844         MMPLAYER_FLEAVE();
5845 }
5846
5847 void
5848 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5849         GstCaps *caps, gpointer data)
5850 {
5851         mmplayer_t *player = (mmplayer_t *)data;
5852         GstPad *pad = NULL;
5853
5854         MMPLAYER_FENTER();
5855
5856         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5857
5858         /* store type string */
5859         MMPLAYER_FREEIF(player->type);
5860         player->type = gst_caps_to_string(caps);
5861         if (player->type)
5862                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5863                                 player, player->type, probability, gst_caps_get_size(caps));
5864
5865         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5866                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5867                 LOGE("not support media format");
5868
5869                 if (player->msg_posted == FALSE) {
5870                         MMMessageParamType msg_param;
5871                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5872
5873                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5874                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5875
5876                         /* don't post more if one was sent already */
5877                         player->msg_posted = TRUE;
5878                 }
5879                 return;
5880         }
5881
5882         __mmplayer_update_content_type_info(player);
5883
5884         pad = gst_element_get_static_pad(tf, "src");
5885         if (!pad) {
5886                 LOGE("fail to get typefind src pad.");
5887                 return;
5888         }
5889
5890         if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5891                 gboolean async = FALSE;
5892                 LOGE("failed to autoplug %s", player->type);
5893
5894                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5895
5896                 if (async && player->msg_posted == FALSE)
5897                         __mmplayer_handle_missed_plugin(player);
5898
5899         }
5900
5901         gst_object_unref(GST_OBJECT(pad));
5902
5903         MMPLAYER_FLEAVE();
5904
5905         return;
5906 }
5907
5908 GstElement *
5909 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5910 {
5911         GstElement *decodebin = NULL;
5912
5913         MMPLAYER_FENTER();
5914
5915         /* create decodebin */
5916         decodebin = gst_element_factory_make("decodebin", NULL);
5917
5918         if (!decodebin) {
5919                 LOGE("fail to create decodebin");
5920                 goto ERROR;
5921         }
5922
5923         /* raw pad handling signal */
5924         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5925                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5926
5927         /* no-more-pad pad handling signal */
5928         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5929                                                 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5930
5931         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5932                                                 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5933
5934         /* This signal is emitted when a pad for which there is no further possible
5935            decoding is added to the decodebin.*/
5936         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5937                                                 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5938
5939         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5940            before looking for any elements that can handle that stream.*/
5941         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5942                                                 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5943
5944         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5945            before looking for any elements that can handle that stream.*/
5946         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5947                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5948
5949         /* This signal is emitted once decodebin has finished decoding all the data.*/
5950         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5951                                                 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5952
5953         /* This signal is emitted when a element is added to the bin.*/
5954         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5955                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5956
5957 ERROR:
5958         return decodebin;
5959 }
5960
5961 static GstElement *
5962 __mmplayer_gst_make_queue2(mmplayer_t *player)
5963 {
5964         GstElement *queue2 = NULL;
5965         gint64 dur_bytes = 0L;
5966         mmplayer_gst_element_t *mainbin = NULL;
5967         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5968
5969         MMPLAYER_FENTER();
5970         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5971
5972         mainbin = player->pipeline->mainbin;
5973
5974         queue2 = gst_element_factory_make("queue2", "queue2");
5975         if (!queue2) {
5976                 LOGE("failed to create buffering queue element");
5977                 return NULL;
5978         }
5979
5980         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5981                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5982
5983         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5984
5985         /* NOTE : in case of ts streaming, player could not get the correct duration info *
5986          *                skip the pull mode(file or ring buffering) setting. */
5987         if (dur_bytes > 0) {
5988                 if (!g_strrstr(player->type, "video/mpegts")) {
5989                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5990                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5991                 }
5992         } else {
5993                 dur_bytes = 0;
5994         }
5995
5996         _mm_player_streaming_set_queue2(player->streamer,
5997                                                                         queue2,
5998                                                                         FALSE,
5999                                                                         type,
6000                                                                         (guint64)dur_bytes); /* no meaning at the moment */
6001
6002         return queue2;
6003 }
6004
6005 gboolean
6006 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6007 {
6008         mmplayer_gst_element_t *mainbin = NULL;
6009         GstElement *decodebin = NULL;
6010         GstElement *queue2 = NULL;
6011         GstPad *sinkpad = NULL;
6012         GstPad *qsrcpad = NULL;
6013
6014         MMPLAYER_FENTER();
6015         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6016
6017         mainbin = player->pipeline->mainbin;
6018
6019         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6020
6021                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6022                         LOGW("need to check: muxed buffer is not null");
6023                 }
6024
6025                 queue2 = __mmplayer_gst_make_queue2(player);
6026                 if (!queue2) {
6027                         LOGE("failed to make queue2");
6028                         goto ERROR;
6029                 }
6030
6031                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6032                         LOGE("failed to add buffering queue");
6033                         goto ERROR;
6034                 }
6035
6036                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6037                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6038
6039                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6040                         LOGE("failed to link [%s:%s]-[%s:%s]",
6041                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6042                         goto ERROR;
6043                 }
6044
6045                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6046                         LOGE("failed to sync queue2 state with parent");
6047                         goto ERROR;
6048                 }
6049
6050                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6051                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6052
6053                 srcpad = qsrcpad;
6054
6055                 gst_object_unref(GST_OBJECT(sinkpad));
6056                 sinkpad = NULL;
6057         }
6058
6059         /* create decodebin */
6060         decodebin = _mmplayer_gst_make_decodebin(player);
6061         if (!decodebin) {
6062                 LOGE("failed to make decodebin");
6063                 goto ERROR;
6064         }
6065
6066         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6067                 LOGE("failed to add decodebin");
6068                 goto ERROR;
6069         }
6070
6071         /* to force caps on the decodebin element and avoid reparsing stuff by
6072         * typefind. It also avoids a deadlock in the way typefind activates pads in
6073         * the state change */
6074         g_object_set(decodebin, "sink-caps", caps, NULL);
6075
6076         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6077
6078         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6079                 LOGE("failed to link [%s:%s]-[%s:%s]",
6080                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6081                 goto ERROR;
6082         }
6083
6084         gst_object_unref(GST_OBJECT(sinkpad));
6085         sinkpad = NULL;
6086         gst_object_unref(GST_OBJECT(qsrcpad));
6087         qsrcpad = NULL;
6088
6089         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6090         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6091
6092         /* set decodebin property about buffer in streaming playback. *
6093          * in case of HLS/DASH, it does not need to have big buffer   *
6094          * because it is kind of adaptive streaming.                  */
6095         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6096                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6097                 gint high_percent = 0;
6098
6099                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6100                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6101
6102                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6103
6104                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6105
6106                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6107                                                                                         "high-percent", high_percent,
6108                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6109                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6110                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6111         }
6112
6113         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6114                 LOGE("failed to sync decodebin state with parent");
6115                 goto ERROR;
6116         }
6117
6118         MMPLAYER_FLEAVE();
6119
6120         return TRUE;
6121
6122 ERROR:
6123
6124         if (sinkpad)
6125                 gst_object_unref(GST_OBJECT(sinkpad));
6126
6127         if (qsrcpad)
6128                 gst_object_unref(GST_OBJECT(qsrcpad));
6129
6130         if (queue2) {
6131                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6132                  * You need to explicitly set elements to the NULL state before
6133                  * dropping the final reference, to allow them to clean up.
6134                  */
6135                 gst_element_set_state(queue2, GST_STATE_NULL);
6136
6137                 /* And, it still has a parent "player".
6138                  * You need to let the parent manage the object instead of unreffing the object directly.
6139                  */
6140                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6141                 gst_object_unref(queue2);
6142                 queue2 = NULL;
6143         }
6144
6145         if (decodebin) {
6146                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6147                  * You need to explicitly set elements to the NULL state before
6148                  * dropping the final reference, to allow them to clean up.
6149                  */
6150                 gst_element_set_state(decodebin, GST_STATE_NULL);
6151
6152                 /* And, it still has a parent "player".
6153                  * You need to let the parent manage the object instead of unreffing the object directly.
6154                  */
6155
6156                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6157                 gst_object_unref(decodebin);
6158                 decodebin = NULL;
6159         }
6160
6161         return FALSE;
6162 }
6163
6164 static int
6165 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6166 {
6167         MMPLAYER_FENTER();
6168
6169         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6170         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6171
6172         LOGD("class : %s, mime : %s", factory_class, mime);
6173
6174         /* add missing plugin */
6175         /* NOTE : msl should check missing plugin for image mime type.
6176          * Some motion jpeg clips can have playable audio track.
6177          * So, msl have to play audio after displaying popup written video format not supported.
6178          */
6179         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6180                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6181                         LOGD("not found demuxer");
6182                         player->not_found_demuxer = TRUE;
6183                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6184
6185                         goto DONE;
6186                 }
6187         }
6188
6189         if (!g_strrstr(factory_class, "Demuxer")) {
6190                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6191                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6192                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6193
6194                         /* check that clip have multi tracks or not */
6195                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6196                                 LOGD("video plugin is already linked");
6197                         } else {
6198                                 LOGW("add VIDEO to missing plugin");
6199                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6200                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6201                         }
6202                 } else if (g_str_has_prefix(mime, "audio")) {
6203                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6204                                 LOGD("audio plugin is already linked");
6205                         } else {
6206                                 LOGW("add AUDIO to missing plugin");
6207                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6208                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6209                         }
6210                 }
6211         }
6212
6213 DONE:
6214         MMPLAYER_FLEAVE();
6215
6216         return MM_ERROR_NONE;
6217 }
6218
6219 static void
6220 __mmplayer_pipeline_complete(GstElement *decodebin,  gpointer data)
6221 {
6222         mmplayer_t *player = (mmplayer_t *)data;
6223
6224         MMPLAYER_FENTER();
6225
6226         MMPLAYER_RETURN_IF_FAIL(player);
6227
6228         /* remove fakesink. */
6229         if (!_mmplayer_gst_remove_fakesink(player,
6230                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6231                 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6232                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6233                  * source element are not same. To overcome this situation, this function will called
6234                  * several places and several times. Therefore, this is not an error case.
6235                  */
6236                 return;
6237         }
6238
6239         LOGD("[handle: %p] pipeline has completely constructed", player);
6240
6241         if ((player->ini.async_start) &&
6242                 (player->msg_posted == FALSE) &&
6243                 (player->cmd >= MMPLAYER_COMMAND_START))
6244                 __mmplayer_handle_missed_plugin(player);
6245
6246         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6247 }
6248
6249 static int
6250 __mmplayer_check_profile(void)
6251 {
6252         char *profileName;
6253         static int profile_tv = -1;
6254
6255         if (__builtin_expect(profile_tv != -1, 1))
6256                 return profile_tv;
6257
6258         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6259         switch (*profileName) {
6260         case 't':
6261         case 'T':
6262                 profile_tv = 1;
6263                 break;
6264         default:
6265                 profile_tv = 0;
6266                 break;
6267         }
6268         free(profileName);
6269
6270         return profile_tv;
6271 }
6272
6273 static gboolean
6274 __mmplayer_get_next_uri(mmplayer_t *player)
6275 {
6276         mmplayer_parse_profile_t profile;
6277         gint uri_idx = 0;
6278         guint num_of_list = 0;
6279         char *uri = NULL;
6280
6281         num_of_list = g_list_length(player->uri_info.uri_list);
6282         uri_idx = player->uri_info.uri_idx;
6283
6284         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6285         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6286                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6287                 if (!uri) {
6288                         LOGW("next uri does not exist");
6289                         continue;
6290                 }
6291
6292                 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6293                         LOGE("failed to parse profile");
6294                         continue;
6295                 }
6296
6297                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6298                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6299                         LOGW("uri type is not supported(%d)", profile.uri_type);
6300                         continue;
6301                 }
6302
6303                 LOGD("success to find next uri %d", uri_idx);
6304                 break;
6305         }
6306
6307         if (!uri || uri_idx == num_of_list) {
6308                 LOGE("failed to find next uri");
6309                 return FALSE;
6310         }
6311
6312         player->uri_info.uri_idx = uri_idx;
6313         if (mm_player_set_attribute((MMHandleType)player, NULL,
6314                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6315                 LOGE("failed to set attribute");
6316                 return FALSE;
6317         }
6318
6319         SECURE_LOGD("next playback uri: %s", uri);
6320         return TRUE;
6321 }
6322
6323 static gboolean
6324 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6325 {
6326 #define REPEAT_COUNT_INFINITE -1
6327 #define REPEAT_COUNT_MIN 2
6328 #define ORIGINAL_URI_ONLY 1
6329
6330         MMHandleType attrs = 0;
6331         gint video = 0;
6332         gint count = 0;
6333         gint gapless = 0;
6334         guint num_of_uri = 0;
6335         int profile_tv = -1;
6336
6337         MMPLAYER_FENTER();
6338
6339         LOGD("checking for gapless play option");
6340
6341         if (player->build_audio_offload) {
6342                 LOGE("offload path is not supportable.");
6343                 goto ERROR;
6344         }
6345
6346         if (player->pipeline->textbin) {
6347                 LOGE("subtitle path is enabled. gapless play is not supported.");
6348                 goto ERROR;
6349         }
6350
6351         attrs = MMPLAYER_GET_ATTRS(player);
6352         if (!attrs) {
6353                 LOGE("fail to get attributes.");
6354                 goto ERROR;
6355         }
6356
6357         mm_attrs_multiple_get(player->attrs, NULL,
6358                         "content_video_found", &video,
6359                         "profile_play_count", &count,
6360                         MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6361
6362         /* gapless playback is not supported in case of video at TV profile. */
6363         profile_tv = __mmplayer_check_profile();
6364         if (profile_tv && video) {
6365                 LOGW("not support video gapless playback");
6366                 goto ERROR;
6367         }
6368
6369         /* check repeat count in case of audio */
6370         if (!gapless &&
6371                 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6372                 LOGW("gapless is disabled");
6373                 goto ERROR;
6374         }
6375
6376         num_of_uri = g_list_length(player->uri_info.uri_list);
6377
6378         LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6379
6380         if (num_of_uri == ORIGINAL_URI_ONLY) {
6381                 /* audio looping path */
6382                 if (count >= REPEAT_COUNT_MIN) {
6383                         /* decrease play count */
6384                         /* we succeeded to rewind. update play count and then wait for next EOS */
6385                         count--;
6386                         mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6387                 } else if (count != REPEAT_COUNT_INFINITE) {
6388                         LOGD("there is no next uri and no repeat");
6389                         goto ERROR;
6390                 }
6391                 LOGD("looping cnt %d", count);
6392         } else {
6393                 /* gapless playback path */
6394                 if (!__mmplayer_get_next_uri(player)) {
6395                         LOGE("failed to get next uri");
6396                         goto ERROR;
6397                 }
6398         }
6399         return TRUE;
6400
6401 ERROR:
6402         LOGE("unable to play gapless path. EOS will be posted soon");
6403         return FALSE;
6404 }
6405
6406 static gboolean
6407 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6408 {
6409         mmplayer_selector_t *selector = &player->selector[type];
6410         mmplayer_gst_element_t *sinkbin = NULL;
6411         main_element_id_e selectorId = MMPLAYER_M_NUM;
6412         main_element_id_e sinkId = MMPLAYER_M_NUM;
6413         GstPad *srcpad = NULL;
6414         GstPad *sinkpad = NULL;
6415         gboolean send_notice = FALSE;
6416
6417         MMPLAYER_FENTER();
6418         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6419
6420         LOGD("type %d", type);
6421
6422         switch (type) {
6423         case MM_PLAYER_TRACK_TYPE_AUDIO:
6424                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6425                 sinkId = MMPLAYER_A_BIN;
6426                 sinkbin = player->pipeline->audiobin;
6427                 break;
6428         case MM_PLAYER_TRACK_TYPE_VIDEO:
6429                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6430                 sinkId = MMPLAYER_V_BIN;
6431                 sinkbin = player->pipeline->videobin;
6432                 send_notice = TRUE;
6433                 break;
6434         case MM_PLAYER_TRACK_TYPE_TEXT:
6435                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6436                 sinkId = MMPLAYER_T_BIN;
6437                 sinkbin = player->pipeline->textbin;
6438                 break;
6439         default:
6440                 LOGE("requested type is not supportable");
6441                 return FALSE;
6442                 break;
6443         }
6444
6445         if (player->pipeline->mainbin[selectorId].gst) {
6446                 gint n;
6447
6448                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6449
6450                 if (selector->event_probe_id != 0)
6451                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6452                 selector->event_probe_id = 0;
6453
6454                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6455                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6456
6457                         if (srcpad && sinkpad) {
6458                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6459                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6460                                 gst_pad_unlink(srcpad, sinkpad);
6461
6462                                 /* send custom event to sink pad to handle it at video sink */
6463                                 if (send_notice) {
6464                                         LOGD("send custom event to sinkpad");
6465                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6466                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6467                                         gst_pad_send_event(sinkpad, event);
6468                                 }
6469                         }
6470
6471                         gst_object_unref(sinkpad);
6472                         sinkpad = NULL;
6473                 }
6474                 gst_object_unref(srcpad);
6475                 srcpad = NULL;
6476
6477                 LOGD("selector release");
6478
6479                 /* release and unref requests pad from the selector */
6480                 for (n = 0; n < selector->channels->len; n++) {
6481                         GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6482                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6483                 }
6484                 g_ptr_array_set_size(selector->channels, 0);
6485
6486                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6487                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6488
6489                 player->pipeline->mainbin[selectorId].gst = NULL;
6490                 selector = NULL;
6491         }
6492
6493         return TRUE;
6494 }
6495
6496 static void
6497 __mmplayer_deactivate_old_path(mmplayer_t *player)
6498 {
6499         MMPLAYER_FENTER();
6500         MMPLAYER_RETURN_IF_FAIL(player);
6501
6502         if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6503                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6504                 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6505                 LOGE("deactivate selector error");
6506                 goto ERROR;
6507         }
6508
6509         _mmplayer_track_destroy(player);
6510         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6511
6512         if (player->streamer) {
6513                 _mm_player_streaming_initialize(player->streamer, FALSE);
6514                 _mm_player_streaming_destroy(player->streamer);
6515                 player->streamer = NULL;
6516         }
6517
6518         MMPLAYER_PLAYBACK_LOCK(player);
6519         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6520
6521         MMPLAYER_FLEAVE();
6522         return;
6523
6524 ERROR:
6525
6526         if (!player->msg_posted) {
6527                 MMMessageParamType msg = {0,};
6528
6529                 /*post error*/
6530                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6531                 LOGE("gapless_uri_play> deactivate error");
6532
6533                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6534                 player->msg_posted = TRUE;
6535         }
6536         return;
6537 }
6538
6539 int
6540 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6541 {
6542         int result = MM_ERROR_NONE;
6543         mmplayer_t *player = (mmplayer_t *)hplayer;
6544         MMPLAYER_FENTER();
6545
6546         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6547         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6548
6549         if (mm_player_set_attribute(hplayer, NULL,
6550                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6551                 LOGE("failed to set attribute");
6552                 result = MM_ERROR_PLAYER_INTERNAL;
6553         } else {
6554                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6555                         LOGE("failed to add the original uri in the uri list.");
6556         }
6557
6558         MMPLAYER_FLEAVE();
6559         return result;
6560 }
6561
6562 int
6563 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6564 {
6565         mmplayer_t *player = (mmplayer_t *)hplayer;
6566         guint num_of_list = 0;
6567
6568         MMPLAYER_FENTER();
6569
6570         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6571         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6572
6573         if (player->pipeline && player->pipeline->textbin) {
6574                 LOGE("subtitle path is enabled.");
6575                 return MM_ERROR_PLAYER_INVALID_STATE;
6576         }
6577
6578         num_of_list = g_list_length(player->uri_info.uri_list);
6579
6580         if (is_first_path) {
6581                 if (num_of_list == 0) {
6582                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6583                         SECURE_LOGD("add original path : %s", uri);
6584                 } else {
6585                         player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6586                         player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6587
6588                         SECURE_LOGD("change original path : %s", uri);
6589                 }
6590         } else {
6591                 MMHandleType attrs = 0;
6592                 attrs = MMPLAYER_GET_ATTRS(player);
6593
6594                 if (num_of_list == 0) {
6595                         char *original_uri = NULL;
6596
6597                         if (attrs) {
6598                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6599
6600                                 if (!original_uri) {
6601                                         LOGE("there is no original uri.");
6602                                         return MM_ERROR_PLAYER_INVALID_STATE;
6603                                 }
6604
6605                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6606                                 player->uri_info.uri_idx = 0;
6607
6608                                 SECURE_LOGD("add original path at first : %s", original_uri);
6609                         }
6610                 }
6611
6612                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6613                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6614         }
6615
6616         MMPLAYER_FLEAVE();
6617         return MM_ERROR_NONE;
6618 }
6619
6620 int
6621 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6622 {
6623         mmplayer_t *player = (mmplayer_t *)hplayer;
6624         char *next_uri = NULL;
6625         guint num_of_list = 0;
6626
6627         MMPLAYER_FENTER();
6628         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6629
6630         num_of_list = g_list_length(player->uri_info.uri_list);
6631
6632         if (num_of_list > 0) {
6633                 gint uri_idx = player->uri_info.uri_idx;
6634
6635                 if (uri_idx < num_of_list-1)
6636                         uri_idx++;
6637                 else
6638                         uri_idx = 0;
6639
6640                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6641                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6642
6643                 *uri = g_strdup(next_uri);
6644         }
6645
6646         MMPLAYER_FLEAVE();
6647         return MM_ERROR_NONE;
6648 }
6649
6650 static void
6651 __mmplayer_gst_decode_unknown_type(GstElement *elem,  GstPad *pad,
6652         GstCaps *caps, gpointer data)
6653 {
6654         mmplayer_t *player = (mmplayer_t *)data;
6655         const gchar *klass = NULL;
6656         const gchar *mime = NULL;
6657         gchar *caps_str = NULL;
6658
6659         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6660         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6661         caps_str = gst_caps_to_string(caps);
6662
6663         LOGW("unknown type of caps : %s from %s",
6664                                         caps_str, GST_ELEMENT_NAME(elem));
6665
6666         MMPLAYER_FREEIF(caps_str);
6667
6668         /* There is no available codec. */
6669         __mmplayer_check_not_supported_codec(player, klass, mime);
6670 }
6671
6672 static gboolean
6673 __mmplayer_gst_decode_autoplug_continue(GstElement *bin,  GstPad *pad,
6674         GstCaps *caps,  gpointer data)
6675 {
6676         mmplayer_t *player = (mmplayer_t *)data;
6677         const char *mime = NULL;
6678         gboolean ret = TRUE;
6679
6680         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6681         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6682
6683         if (g_str_has_prefix(mime, "audio")) {
6684                 GstStructure *caps_structure = NULL;
6685                 gint samplerate = 0;
6686                 gint channels = 0;
6687                 gchar *caps_str = NULL;
6688
6689                 caps_structure = gst_caps_get_structure(caps, 0);
6690                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6691                 gst_structure_get_int(caps_structure, "channels", &channels);
6692
6693                 if ((channels > 0 && samplerate == 0)) {
6694                         LOGD("exclude audio...");
6695                         ret = FALSE;
6696                 }
6697
6698                 caps_str = gst_caps_to_string(caps);
6699                 /* set it directly because not sent by TAG */
6700                 if (g_strrstr(caps_str, "mobile-xmf"))
6701                         mm_player_set_attribute((MMHandleType)player, NULL,
6702                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6703
6704                 MMPLAYER_FREEIF(caps_str);
6705         } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6706                 MMMessageParamType msg_param;
6707                 memset(&msg_param, 0, sizeof(MMMessageParamType));
6708                 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6709                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6710                 LOGD("video file is not supported on this device");
6711                 ret = FALSE;
6712         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6713                 LOGD("already video linked");
6714                 ret = FALSE;
6715         } else {
6716                 LOGD("found new stream");
6717         }
6718
6719         return ret;
6720 }
6721
6722 static gboolean
6723 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6724 {
6725         gboolean ret = TRUE;
6726         GDBusConnection *conn = NULL;
6727         GError *err = NULL;
6728         GVariant *result = NULL;
6729         const gchar *dbus_device_type = NULL;
6730         const gchar *dbus_ret = NULL;
6731         gint idx = 0;
6732
6733         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6734         if (!conn || err) {
6735                 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6736                 g_error_free(err);
6737                 ret = FALSE;
6738                 goto DONE;
6739         }
6740
6741         result = g_dbus_connection_call_sync(conn,
6742                                         "org.pulseaudio.Server",
6743                                         "/org/pulseaudio/StreamManager",
6744                                         "org.pulseaudio.StreamManager",
6745                                         "GetCurrentMediaRoutingPath",
6746                                         g_variant_new("(s)", "out"),
6747                                         G_VARIANT_TYPE("(ss)"),
6748                                         G_DBUS_CALL_FLAGS_NONE,
6749                                         2000,
6750                                         NULL,
6751                                         &err);
6752         if (!result || err) {
6753                 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6754                 g_error_free(err);
6755                 ret = FALSE;
6756                 goto DONE;
6757         }
6758
6759         /* device type is listed in stream-map.json at mmfw-sysconf */
6760         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6761
6762         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6763         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6764                 ret = FALSE;
6765                 goto DONE;
6766         }
6767
6768         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6769         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6770                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6771                         LOGD("audio offload is supportable");
6772                         ret = TRUE;
6773                         goto DONE;
6774                 }
6775         }
6776
6777         LOGD("audio offload is not supportable");
6778         ret = FALSE;
6779
6780 DONE:
6781         g_variant_unref(result);
6782         g_object_unref(conn);
6783
6784         return ret;
6785 }
6786
6787 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6788 {
6789         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6790         gint64 position = 0;
6791
6792         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6793                 player->pipeline && player->pipeline->mainbin);
6794
6795         MMPLAYER_CMD_LOCK(player);
6796         current_state = MMPLAYER_CURRENT_STATE(player);
6797
6798         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6799                 LOGW("getting current position failed in paused");
6800
6801         _mmplayer_unrealize((MMHandleType)player);
6802         _mmplayer_realize((MMHandleType)player);
6803
6804         _mmplayer_set_position((MMHandleType)player, position);
6805
6806         /* async not to be blocked in streaming case */
6807         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6808
6809         _mmplayer_pause((MMHandleType)player);
6810
6811         if (current_state == MM_PLAYER_STATE_PLAYING)
6812                 _mmplayer_start((MMHandleType)player);
6813         MMPLAYER_CMD_UNLOCK(player);
6814
6815         LOGD("rebuilding audio pipeline is completed.");
6816 }
6817
6818 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6819 {
6820         mmplayer_t *player = (mmplayer_t *)user_data;
6821         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6822         gboolean is_supportable = FALSE;
6823
6824         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6825                 LOGW("failed to get device type");
6826         else
6827                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6828
6829         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6830                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6831                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6832                 LOGD("ignore this dev connected info");
6833                 return;
6834         }
6835
6836         is_supportable = __mmplayer_is_audio_offload_device_type(player);
6837         if (player->build_audio_offload == is_supportable) {
6838                 LOGD("keep current pipeline without re-building");
6839                 return;
6840         }
6841
6842         /* rebuild pipeline */
6843         LOGD("re-build pipeline - offload: %d", is_supportable);
6844         player->build_audio_offload = FALSE;
6845         __mmplayer_rebuild_audio_pipeline(player);
6846
6847         return;
6848 }
6849
6850 static gboolean
6851 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6852 {
6853         unsigned int id = 0;
6854
6855         if (player->audio_device_cb_id != 0) {
6856                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6857                 return TRUE;
6858         }
6859
6860         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6861                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6862                 LOGD("added device connected cb (%u)", id);
6863                 player->audio_device_cb_id = id;
6864         } else {
6865                 LOGW("failed to add device connected cb");
6866                 return FALSE;
6867         }
6868
6869         return TRUE;
6870 }
6871
6872 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6873 {
6874         mmplayer_t *player = (mmplayer_t *)hplayer;
6875
6876         MMPLAYER_FENTER();
6877         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6878         MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6879
6880         *activated = player->build_audio_offload;
6881
6882         LOGD("offload activated : %d", (int)*activated);
6883
6884         MMPLAYER_FLEAVE();
6885         return MM_ERROR_NONE;
6886 }
6887
6888 static gboolean
6889 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6890 {
6891         /* NOTE :
6892            this function need to be updated according to the supported media format
6893            @see player->ini.audio_offload_media_format */
6894
6895         if (__mmplayer_is_only_mp3_type(player->type)) {
6896                 LOGD("offload supportable media format type");
6897                 return TRUE;
6898         }
6899
6900         return FALSE;
6901 }
6902
6903 static gboolean
6904 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6905 {
6906         gboolean ret = FALSE;
6907         GstElementFactory *factory = NULL;
6908
6909         MMPLAYER_FENTER();
6910         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6911
6912         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6913         if (!__mmplayer_is_offload_supported_type(player))
6914                 goto DONE;
6915
6916         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6917                 LOGD("there is no audio offload sink");
6918                 goto DONE;
6919         }
6920
6921         if (player->ini.audio_offload_device_type[0][0] == '\0') {
6922                 LOGW("there is no audio device type to support offload");
6923                 goto DONE;
6924         }
6925
6926         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6927         if (!factory) {
6928                 LOGW("there is no installed audio offload sink element");
6929                 goto DONE;
6930         }
6931         gst_object_unref(factory);
6932
6933         if (__mmplayer_acquire_hw_resource(player,
6934                         MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6935                 LOGE("failed to acquire audio offload decoder resource");
6936                 goto DONE;
6937         }
6938
6939         if (!__mmplayer_add_audio_device_connected_cb(player))
6940                 goto DONE;
6941
6942         if (!__mmplayer_is_audio_offload_device_type(player))
6943                 goto DONE;
6944
6945         LOGD("audio offload can be built");
6946         ret = TRUE;
6947
6948 DONE:
6949         if (!ret)
6950                 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6951
6952         MMPLAYER_FLEAVE();
6953         return ret;
6954 }
6955
6956 static GstAutoplugSelectResult
6957 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6958 {
6959         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6960         int idx = 0;
6961         int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6962         int audio_offload = 0;
6963
6964         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6965                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6966
6967                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6968                         LOGD("expose audio path to build offload output path");
6969                         player->build_audio_offload = TRUE;
6970                         /* update codec info */
6971                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6972                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6973                         player->audiodec_linked = 1;
6974
6975                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
6976                         goto DONE;
6977                 }
6978
6979                 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6980
6981                 LOGD("audio codec type: %d", codec_type);
6982                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6983                         /* sw codec will be skipped */
6984                         for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6985                                 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6986                                         LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6987                                         ret = GST_AUTOPLUG_SELECT_SKIP;
6988                                         goto DONE;
6989                                 }
6990                         }
6991                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6992                         /* hw codec will be skipped */
6993                         if (strcmp(player->ini.audiocodec_element_hw, "") &&
6994                             g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6995                                 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6996                                 ret = GST_AUTOPLUG_SELECT_SKIP;
6997                                 goto DONE;
6998                         }
6999                 }
7000
7001                 /* set stream information */
7002                 if (!player->audiodec_linked)
7003                         __mmplayer_set_audio_attrs(player, caps);
7004
7005                 /* update codec info */
7006                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7007                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7008                 player->audiodec_linked = 1;
7009
7010         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7011
7012                 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7013
7014                 LOGD("video codec type: %d", codec_type);
7015                 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7016                         /* sw codec is skipped */
7017                         for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7018                                 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7019                                         LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7020                                         ret = GST_AUTOPLUG_SELECT_SKIP;
7021                                         goto DONE;
7022                                 }
7023                         }
7024                 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7025                         /* hw codec is skipped */
7026                         if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7027                                 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7028                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7029                                 goto DONE;
7030                         }
7031                 }
7032
7033                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7034                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7035
7036                         /* mark video decoder for acquire */
7037                         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7038                                 LOGW("video decoder resource is already acquired, skip it.");
7039                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7040                                 goto DONE;
7041                         }
7042
7043                         if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7044                                 LOGE("failed to acquire video decoder resource");
7045                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7046                                 goto DONE;
7047                         }
7048                         player->interrupted_by_resource = FALSE;
7049                 }
7050
7051                 /* update codec info */
7052                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7053                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7054                 player->videodec_linked = 1;
7055         }
7056
7057 DONE:
7058         return ret;
7059 }
7060
7061 gint
7062 _mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7063         GstCaps *caps, GstElementFactory *factory, gpointer data)
7064 {
7065         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7066         mmplayer_t *player = (mmplayer_t *)data;
7067
7068         gchar *factory_name = NULL;
7069         gchar *caps_str = NULL;
7070         const gchar *klass = NULL;
7071         gint idx = 0;
7072
7073         factory_name = GST_OBJECT_NAME(factory);
7074         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7075         caps_str = gst_caps_to_string(caps);
7076
7077         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7078
7079         /* store type string */
7080         if (player->type == NULL) {
7081                 player->type = gst_caps_to_string(caps);
7082                 __mmplayer_update_content_type_info(player);
7083         }
7084
7085         /* filtering exclude keyword */
7086         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7087                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7088                         LOGW("skipping [%s] by exculde keyword [%s]",
7089                                         factory_name, player->ini.exclude_element_keyword[idx]);
7090
7091                         result = GST_AUTOPLUG_SELECT_SKIP;
7092                         goto DONE;
7093                 }
7094         }
7095
7096         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7097                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7098                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7099                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7100                         result = GST_AUTOPLUG_SELECT_SKIP;
7101                         goto DONE;
7102                 }
7103         }
7104
7105         /* exclude webm format */
7106         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7107          * because webm format is not supportable.
7108          * If webm is disabled in "autoplug-continue", there is no state change
7109          * failure or error because the decodebin will expose the pad directly.
7110          * It make MSL invoke _prepare_async_callback.
7111          * So, we need to disable webm format in "autoplug-select" */
7112         if (caps_str && strstr(caps_str, "webm")) {
7113                 LOGW("webm is not supported");
7114                 result = GST_AUTOPLUG_SELECT_SKIP;
7115                 goto DONE;
7116         }
7117
7118         /* check factory class for filtering */
7119         /* NOTE : msl don't need to use image plugins.
7120          * So, those plugins should be skipped for error handling.
7121          */
7122         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7123                 LOGD("skipping [%s] by not required", factory_name);
7124                 result = GST_AUTOPLUG_SELECT_SKIP;
7125                 goto DONE;
7126         }
7127
7128         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7129                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7130                 // TO CHECK : subtitle if needed, add subparse exception.
7131                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7132                 result = GST_AUTOPLUG_SELECT_SKIP;
7133                 goto DONE;
7134         }
7135
7136         if (g_strrstr(factory_name, "mpegpsdemux")) {
7137                 LOGD("skipping PS container - not support");
7138                 result = GST_AUTOPLUG_SELECT_SKIP;
7139                 goto DONE;
7140         }
7141
7142         if (g_strrstr(factory_name, "mssdemux"))
7143                 player->smooth_streaming = TRUE;
7144
7145         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7146                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7147                 gint stype = 0;
7148                 gint width = 0;
7149                 GstStructure *str = NULL;
7150                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7151
7152                 /* don't make video because of not required */
7153                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7154                         (!player->set_mode.video_export)) {
7155                         LOGD("no need video decoding, expose pad");
7156                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7157                         goto DONE;
7158                 }
7159
7160                 /* get w/h for omx state-tune */
7161                 /* FIXME: deprecated? */
7162                 str = gst_caps_get_structure(caps, 0);
7163                 gst_structure_get_int(str, "width", &width);
7164
7165                 if (width != 0) {
7166                         if (player->v_stream_caps) {
7167                                 gst_caps_unref(player->v_stream_caps);
7168                                 player->v_stream_caps = NULL;
7169                         }
7170
7171                         player->v_stream_caps = gst_caps_copy(caps);
7172                         LOGD("take caps for video state tune");
7173                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7174                 }
7175         }
7176
7177         if (g_strrstr(klass, "Codec/Decoder")) {
7178                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7179                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7180                         LOGW("skip add decoder");
7181                         goto DONE;
7182                 }
7183         }
7184
7185 DONE:
7186         MMPLAYER_FREEIF(caps_str);
7187
7188         return result;
7189 }
7190
7191 static void
7192 __mmplayer_gst_decode_pad_removed(GstElement *elem,  GstPad *new_pad,
7193         gpointer data)
7194 {
7195         //mmplayer_t *player = (mmplayer_t *)data;
7196         GstCaps *caps = NULL;
7197
7198         LOGD("[Decodebin2] pad-removed signal");
7199
7200         caps = gst_pad_query_caps(new_pad, NULL);
7201         if (!caps) {
7202                 LOGW("query caps is NULL");
7203                 return;
7204         }
7205
7206         gchar *caps_str = NULL;
7207         caps_str = gst_caps_to_string(caps);
7208
7209         LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7210
7211         MMPLAYER_FREEIF(caps_str);
7212         gst_caps_unref(caps);
7213 }
7214
7215 static void
7216 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7217 {
7218         mmplayer_t *player = (mmplayer_t *)data;
7219         GstIterator *iter = NULL;
7220         GValue item = { 0, };
7221         GstPad *pad = NULL;
7222         gboolean done = FALSE;
7223         gboolean is_all_drained = TRUE;
7224
7225         MMPLAYER_FENTER();
7226         MMPLAYER_RETURN_IF_FAIL(player);
7227
7228         LOGD("__mmplayer_gst_decode_drained");
7229
7230         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7231                 LOGW("Fail to get cmd lock");
7232                 return;
7233         }
7234
7235         if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7236                 !__mmplayer_verify_gapless_play_path(player)) {
7237                 LOGD("decoding is finished.");
7238                 __mmplayer_reset_gapless_state(player);
7239                 MMPLAYER_CMD_UNLOCK(player);
7240                 return;
7241         }
7242
7243         player->gapless.reconfigure = TRUE;
7244
7245         /* check decodebin src pads whether they received EOS or not */
7246         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7247
7248         while (!done) {
7249                 switch (gst_iterator_next(iter, &item)) {
7250                 case GST_ITERATOR_OK:
7251                         pad = g_value_get_object(&item);
7252                         if (pad && !GST_PAD_IS_EOS(pad)) {
7253                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7254                                 is_all_drained = FALSE;
7255                                 break;
7256                         }
7257                         g_value_reset(&item);
7258                         break;
7259                 case GST_ITERATOR_RESYNC:
7260                         gst_iterator_resync(iter);
7261                         break;
7262                 case GST_ITERATOR_ERROR:
7263                 case GST_ITERATOR_DONE:
7264                         done = TRUE;
7265                         break;
7266                 }
7267         }
7268         g_value_unset(&item);
7269         gst_iterator_free(iter);
7270
7271         if (!is_all_drained) {
7272                 LOGD("Wait util the all pads get EOS.");
7273                 MMPLAYER_CMD_UNLOCK(player);
7274                 MMPLAYER_FLEAVE();
7275                 return;
7276         }
7277
7278         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7279         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7280
7281         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7282         MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7283         __mmplayer_deactivate_old_path(player);
7284         MMPLAYER_CMD_UNLOCK(player);
7285
7286         MMPLAYER_FLEAVE();
7287 }
7288
7289 void
7290 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7291 {
7292         mmplayer_t *player = (mmplayer_t *)data;
7293         const gchar *klass = NULL;
7294         gchar *factory_name = NULL;
7295
7296         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7297         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7298
7299         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7300
7301         if (__mmplayer_add_dump_buffer_probe(player, element))
7302                 LOGD("add buffer probe");
7303
7304         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7305                 gchar *selected = NULL;
7306                 selected = g_strdup(GST_ELEMENT_NAME(element));
7307                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7308         }
7309
7310         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7311                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7312                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7313
7314                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7315                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7316
7317                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7318                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7319                                                 "max-video-width", player->adaptive_info.limit.width,
7320                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7321
7322         } else if (g_strrstr(klass, "Demuxer")) {
7323 #ifdef __DEBUG__
7324                 LOGD("plugged element is demuxer. take it");
7325 #endif
7326                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7327                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7328         }
7329
7330         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7331                 int surface_type = 0;
7332
7333                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7334         }
7335
7336         // to support trust-zone only
7337         if (g_strrstr(factory_name, "asfdemux")) {
7338                 LOGD("set file-location %s", player->profile.uri);
7339                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7340         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7341                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7342                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7343         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7344                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7345                         (__mmplayer_is_only_mp3_type(player->type))) {
7346                         LOGD("[mpegaudioparse] set streaming pull mode.");
7347                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7348                 }
7349         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7350                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7351         }
7352
7353         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7354                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7355                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7356
7357                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7358                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7359
7360                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7361                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7362                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7363                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7364                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7365                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7366                 }
7367
7368         }
7369
7370         return;
7371 }
7372
7373 static void
7374 __mmplayer_release_misc(mmplayer_t *player)
7375 {
7376         int i;
7377         bool cur_mode = player->set_mode.rich_audio;
7378         MMPLAYER_FENTER();
7379
7380         MMPLAYER_RETURN_IF_FAIL(player);
7381
7382         player->video_decoded_cb = NULL;
7383         player->video_decoded_cb_user_param = NULL;
7384         player->video_stream_prerolled = false;
7385
7386         player->audio_decoded_cb = NULL;
7387         player->audio_decoded_cb_user_param = NULL;
7388         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7389
7390         player->audio_stream_changed_cb = NULL;
7391         player->audio_stream_changed_cb_user_param = NULL;
7392
7393         player->sent_bos = FALSE;
7394         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7395
7396         player->seek_state = MMPLAYER_SEEK_NONE;
7397
7398         player->total_bitrate = 0;
7399         player->total_maximum_bitrate = 0;
7400
7401         player->not_found_demuxer = 0;
7402
7403         player->last_position = 0;
7404         player->duration = 0;
7405         player->http_content_size = 0;
7406         player->not_supported_codec = MISSING_PLUGIN_NONE;
7407         player->can_support_codec = FOUND_PLUGIN_NONE;
7408         player->pending_seek.is_pending = false;
7409         player->pending_seek.pos = 0;
7410         player->msg_posted = FALSE;
7411         player->has_many_types = FALSE;
7412         player->is_subtitle_force_drop = FALSE;
7413         player->play_subtitle = FALSE;
7414         player->adjust_subtitle_pos = 0;
7415         player->has_closed_caption = FALSE;
7416         player->set_mode.video_export = false;
7417         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7418         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7419         /* recover mode */
7420         player->set_mode.rich_audio = cur_mode;
7421
7422         if (player->audio_device_cb_id > 0 &&
7423                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7424                 LOGW("failed to remove audio device_connected_callback");
7425         player->audio_device_cb_id = 0;
7426
7427         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7428                 player->bitrate[i] = 0;
7429                 player->maximum_bitrate[i] = 0;
7430         }
7431
7432         /* free memory related to audio effect */
7433         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7434
7435         if (player->adaptive_info.var_list) {
7436                 g_list_free_full(player->adaptive_info.var_list, g_free);
7437                 player->adaptive_info.var_list = NULL;
7438         }
7439
7440         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7441         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7442         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7443
7444         /* Reset video360 settings to their defaults in case if the pipeline is to be
7445          * re-created.
7446          * */
7447         player->video360_metadata.is_spherical = -1;
7448         player->is_openal_plugin_used = FALSE;
7449
7450         player->is_content_spherical = FALSE;
7451         player->is_video360_enabled = TRUE;
7452         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7453         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7454         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7455         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7456         player->video360_zoom = 1.0f;
7457         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7458         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7459
7460         player->sound.rg_enable = false;
7461
7462         __mmplayer_initialize_video_roi(player);
7463         MMPLAYER_FLEAVE();
7464 }
7465
7466 static void
7467 __mmplayer_release_misc_post(mmplayer_t *player)
7468 {
7469         char *original_uri = NULL;
7470         MMPLAYER_FENTER();
7471
7472         /* player->pipeline is already released before. */
7473
7474         MMPLAYER_RETURN_IF_FAIL(player);
7475
7476         mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7477
7478         /* clean found audio decoders */
7479         if (player->audio_decoders) {
7480                 GList *a_dec = player->audio_decoders;
7481                 for (; a_dec; a_dec = g_list_next(a_dec)) {
7482                         gchar *name = a_dec->data;
7483                         MMPLAYER_FREEIF(name);
7484                 }
7485                 g_list_free(player->audio_decoders);
7486                 player->audio_decoders = NULL;
7487         }
7488
7489         /* clean the uri list except original uri */
7490         if (player->uri_info.uri_list) {
7491                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7492
7493                 if (!original_uri)
7494                         LOGW("failed to get original uri info");
7495
7496                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7497                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7498
7499                 GList *uri_list = player->uri_info.uri_list;
7500                 for (; uri_list; uri_list = g_list_next(uri_list)) {
7501                         gchar *uri = uri_list->data;
7502                         MMPLAYER_FREEIF(uri);
7503                 }
7504                 g_list_free(player->uri_info.uri_list);
7505                 player->uri_info.uri_list = NULL;
7506         }
7507
7508         /* clear the audio stream buffer list */
7509         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7510
7511         /* clear the video stream bo list */
7512         __mmplayer_video_stream_destroy_bo_list(player);
7513         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7514
7515         if (player->profile.input_mem.buf) {
7516                 free(player->profile.input_mem.buf);
7517                 player->profile.input_mem.buf = NULL;
7518         }
7519         player->profile.input_mem.len = 0;
7520         player->profile.input_mem.offset = 0;
7521
7522         player->uri_info.uri_idx = 0;
7523         MMPLAYER_FLEAVE();
7524 }
7525
7526 gboolean
7527 __mmplayer_check_subtitle(mmplayer_t *player)
7528 {
7529         MMHandleType attrs = 0;
7530         char *subtitle_uri = NULL;
7531
7532         MMPLAYER_FENTER();
7533
7534         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7535
7536         /* get subtitle attribute */
7537         attrs = MMPLAYER_GET_ATTRS(player);
7538         if (!attrs)
7539                 return FALSE;
7540
7541         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7542         if (!subtitle_uri || !strlen(subtitle_uri))
7543                 return FALSE;
7544
7545         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7546         player->is_external_subtitle_present = TRUE;
7547
7548         MMPLAYER_FLEAVE();
7549
7550         return TRUE;
7551 }
7552
7553 void
7554 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7555 {
7556         MMPLAYER_RETURN_IF_FAIL(player);
7557
7558         if (player->eos_timer) {
7559                 LOGD("cancel eos timer");
7560                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7561                 player->eos_timer = 0;
7562         }
7563
7564         return;
7565 }
7566
7567 static void
7568 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7569 {
7570         MMPLAYER_FENTER();
7571
7572         MMPLAYER_RETURN_IF_FAIL(player);
7573         MMPLAYER_RETURN_IF_FAIL(sink);
7574
7575         player->sink_elements = g_list_append(player->sink_elements, sink);
7576
7577         MMPLAYER_FLEAVE();
7578 }
7579
7580 static void
7581 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7582 {
7583         MMPLAYER_FENTER();
7584
7585         MMPLAYER_RETURN_IF_FAIL(player);
7586         MMPLAYER_RETURN_IF_FAIL(sink);
7587
7588         player->sink_elements = g_list_remove(player->sink_elements, sink);
7589
7590         MMPLAYER_FLEAVE();
7591 }
7592
7593 void
7594 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7595         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7596 {
7597         mmplayer_signal_item_t *item = NULL;
7598
7599         MMPLAYER_FENTER();
7600         MMPLAYER_RETURN_IF_FAIL(player);
7601
7602         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7603                 LOGE("invalid signal type [%d]", type);
7604                 return;
7605         }
7606
7607         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7608         if (!item) {
7609                 LOGE("cannot connect signal [%s]", signal);
7610                 return;
7611         }
7612
7613         item->obj = object;
7614         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7615         player->signals[type] = g_list_append(player->signals[type], item);
7616
7617         MMPLAYER_FLEAVE();
7618         return;
7619 }
7620
7621 /* NOTE : be careful with calling this api. please refer to below glib comment
7622  * glib comment : Note that there is a bug in GObject that makes this function much
7623  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7624  * will no longer be called, but, the signal handler is not currently disconnected.
7625  * If the instance is itself being freed at the same time than this doesn't matter,
7626  * since the signal will automatically be removed, but if instance persists,
7627  * then the signal handler will leak. You should not remove the signal yourself
7628  * because in a future versions of GObject, the handler will automatically be
7629  * disconnected.
7630  *
7631  * It's possible to work around this problem in a way that will continue to work
7632  * with future versions of GObject by checking that the signal handler is still
7633  * connected before disconnected it:
7634  *
7635  *  if (g_signal_handler_is_connected(instance, id))
7636  *    g_signal_handler_disconnect(instance, id);
7637  */
7638 static void
7639 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7640 {
7641         GList *sig_list = NULL;
7642         mmplayer_signal_item_t *item = NULL;
7643
7644         MMPLAYER_FENTER();
7645
7646         MMPLAYER_RETURN_IF_FAIL(player);
7647
7648         LOGD("release signals type : %d", type);
7649
7650         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7651                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7652                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7653                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7654                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7655                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7656                 return;
7657         }
7658
7659         sig_list = player->signals[type];
7660
7661         for (; sig_list; sig_list = sig_list->next) {
7662                 item = sig_list->data;
7663
7664                 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7665                         if (g_signal_handler_is_connected(item->obj, item->sig))
7666                                 g_signal_handler_disconnect(item->obj, item->sig);
7667                 }
7668
7669                 MMPLAYER_FREEIF(item);
7670         }
7671
7672         g_list_free(player->signals[type]);
7673         player->signals[type] = NULL;
7674
7675         MMPLAYER_FLEAVE();
7676
7677         return;
7678 }
7679
7680 int
7681 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, unsigned int wl_surface_id)
7682 {
7683         mmplayer_t *player = 0;
7684         int prev_display_surface_type = 0;
7685
7686         MMPLAYER_FENTER();
7687
7688         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7689
7690         player = MM_PLAYER_CAST(handle);
7691
7692         /* check video sinkbin is created */
7693         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7694                 LOGW("Videosink is already created");
7695                 return MM_ERROR_NONE;
7696         }
7697
7698         LOGD("videosink element is not yet ready");
7699
7700         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7701                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7702                 MMPLAYER_FLEAVE();
7703                 return MM_ERROR_INVALID_ARGUMENT;
7704         }
7705
7706         /* load previous attributes */
7707         if (player->attrs) {
7708                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7709                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7710                 if (prev_display_surface_type == surface_type) {
7711                         LOGD("incoming display surface type is same as previous one, do nothing..");
7712                         MMPLAYER_FLEAVE();
7713                         return MM_ERROR_NONE;
7714                 }
7715         } else {
7716                 LOGE("failed to load attributes");
7717                 MMPLAYER_FLEAVE();
7718                 return MM_ERROR_PLAYER_INTERNAL;
7719         }
7720
7721         /* videobin is not created yet, so we just set attributes related to display surface */
7722         LOGD("store display attribute for given surface type(%d)", surface_type);
7723         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7724                         "display_overlay", (int)wl_surface_id, NULL);
7725
7726         MMPLAYER_FLEAVE();
7727         return MM_ERROR_NONE;
7728 }
7729
7730 /* Note : if silent is true, then subtitle would not be displayed. :*/
7731 int
7732 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7733 {
7734         mmplayer_t *player = (mmplayer_t *)hplayer;
7735
7736         MMPLAYER_FENTER();
7737
7738         /* check player handle */
7739         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7740
7741         player->set_mode.subtitle_off = silent;
7742
7743         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7744
7745         MMPLAYER_FLEAVE();
7746
7747         return MM_ERROR_NONE;
7748 }
7749
7750 int
7751 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7752 {
7753         mmplayer_gst_element_t *mainbin = NULL;
7754         mmplayer_gst_element_t *textbin = NULL;
7755         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7756         GstState current_state = GST_STATE_VOID_PENDING;
7757         GstState element_state = GST_STATE_VOID_PENDING;
7758         GstState element_pending_state = GST_STATE_VOID_PENDING;
7759         gint64 time = 0;
7760         GstEvent *event = NULL;
7761         int result = MM_ERROR_NONE;
7762
7763         GstClock *curr_clock = NULL;
7764         GstClockTime base_time, start_time, curr_time;
7765
7766
7767         MMPLAYER_FENTER();
7768
7769         /* check player handle */
7770         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7771                                                                 player->pipeline &&
7772                                                                 player->pipeline->mainbin &&
7773                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7774
7775         mainbin = player->pipeline->mainbin;
7776         textbin = player->pipeline->textbin;
7777
7778         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7779
7780         // sync clock with current pipeline
7781         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7782         curr_time = gst_clock_get_time(curr_clock);
7783
7784         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7785         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7786
7787         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7788                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7789
7790         if (current_state > GST_STATE_READY) {
7791                 // sync state with current pipeline
7792                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7793                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7794                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7795
7796                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7797                 if (GST_STATE_CHANGE_FAILURE == ret) {
7798                         LOGE("fail to state change.");
7799                         result = MM_ERROR_PLAYER_INTERNAL;
7800                         goto ERROR;
7801                 }
7802         }
7803         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7804         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7805
7806         if (curr_clock) {
7807                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7808                 gst_object_unref(curr_clock);
7809         }
7810
7811         // seek to current position
7812         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7813                 result = MM_ERROR_PLAYER_INVALID_STATE;
7814                 LOGE("gst_element_query_position failed, invalid state");
7815                 goto ERROR;
7816         }
7817
7818         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7819         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);
7820         if (event) {
7821                 _mmplayer_gst_send_event_to_sink(player, event);
7822         } else {
7823                 result = MM_ERROR_PLAYER_INTERNAL;
7824                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7825                 goto ERROR;
7826         }
7827
7828         /* sync state with current pipeline */
7829         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7830         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7831         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7832
7833         return MM_ERROR_NONE;
7834
7835 ERROR:
7836         /* release text pipeline resource */
7837         player->textsink_linked = 0;
7838
7839         /* release signal */
7840         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7841
7842         /* release textbin with it's childs */
7843         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7844         MMPLAYER_FREEIF(player->pipeline->textbin);
7845         player->pipeline->textbin = NULL;
7846
7847         /* release subtitle elem */
7848         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7849         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7850
7851         return result;
7852 }
7853
7854 static int
7855 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7856 {
7857         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7858         GstState current_state = GST_STATE_VOID_PENDING;
7859
7860         MMHandleType attrs = 0;
7861         mmplayer_gst_element_t *mainbin = NULL;
7862         mmplayer_gst_element_t *textbin = NULL;
7863
7864         gchar *subtitle_uri = NULL;
7865         int result = MM_ERROR_NONE;
7866         const gchar *charset = NULL;
7867
7868         MMPLAYER_FENTER();
7869
7870         /* check player handle */
7871         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7872                                                                 player->pipeline &&
7873                                                                 player->pipeline->mainbin &&
7874                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7875         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7876
7877         mainbin = player->pipeline->mainbin;
7878         textbin = player->pipeline->textbin;
7879
7880         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7881         if (current_state < GST_STATE_READY) {
7882                 result = MM_ERROR_PLAYER_INVALID_STATE;
7883                 LOGE("Pipeline is not in proper state");
7884                 goto EXIT;
7885         }
7886
7887         attrs = MMPLAYER_GET_ATTRS(player);
7888         if (!attrs) {
7889                 LOGE("cannot get content attribute");
7890                 result = MM_ERROR_PLAYER_INTERNAL;
7891                 goto EXIT;
7892         }
7893
7894         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7895         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7896                 LOGE("subtitle uri is not proper filepath");
7897                 result = MM_ERROR_PLAYER_INVALID_URI;
7898                 goto EXIT;
7899         }
7900
7901         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7902                 LOGE("failed to get storage info of subtitle path");
7903                 result = MM_ERROR_PLAYER_INVALID_URI;
7904                 goto EXIT;
7905         }
7906
7907         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7908         SECURE_LOGD("new subtitle file path is [%s]", filepath);
7909
7910         if (!strcmp(filepath, subtitle_uri)) {
7911                 LOGD("subtitle path is not changed");
7912                 goto EXIT;
7913         } else {
7914                 if (mm_player_set_attribute((MMHandleType)player, NULL,
7915                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7916                         LOGE("failed to set attribute");
7917                         goto EXIT;
7918                 }
7919         }
7920
7921         //gst_pad_set_blocked_async(src-srcpad, TRUE)
7922         MMPLAYER_SUBTITLE_INFO_LOCK(player);
7923         player->subtitle_language_list = NULL;
7924         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7925
7926         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7927         if (ret != GST_STATE_CHANGE_SUCCESS) {
7928                 LOGE("failed to change state of textbin to READY");
7929                 result = MM_ERROR_PLAYER_INTERNAL;
7930                 goto EXIT;
7931         }
7932
7933         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7934         if (ret != GST_STATE_CHANGE_SUCCESS) {
7935                 LOGE("failed to change state of subparse to READY");
7936                 result = MM_ERROR_PLAYER_INTERNAL;
7937                 goto EXIT;
7938         }
7939
7940         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7941         if (ret != GST_STATE_CHANGE_SUCCESS) {
7942                 LOGE("failed to change state of filesrc to READY");
7943                 result = MM_ERROR_PLAYER_INTERNAL;
7944                 goto EXIT;
7945         }
7946
7947         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7948
7949         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7950
7951         charset = _mmplayer_get_charset(filepath);
7952         if (charset) {
7953                 LOGD("detected charset is %s", charset);
7954                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7955         }
7956
7957         result = _mmplayer_sync_subtitle_pipeline(player);
7958
7959 EXIT:
7960         MMPLAYER_FLEAVE();
7961         return result;
7962 }
7963
7964 /* API to switch between external subtitles */
7965 int
7966 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7967 {
7968         int result = MM_ERROR_NONE;
7969         mmplayer_t *player = (mmplayer_t *)hplayer;
7970         char *path = NULL;
7971
7972         MMPLAYER_FENTER();
7973
7974         /* check player handle */
7975         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7976
7977         /* filepath can be null in idle state */
7978         if (filepath) {
7979                 /* check file path */
7980                 if ((path = strstr(filepath, "file://")))
7981                         result = _mmplayer_exist_file_path(path + 7);
7982                 else
7983                         result = _mmplayer_exist_file_path(filepath);
7984
7985                 if (result != MM_ERROR_NONE) {
7986                         LOGE("invalid subtitle path 0x%X", result);
7987                         return result; /* file not found or permission denied */
7988                 }
7989         }
7990
7991         if (!player->pipeline) {
7992                 /* IDLE state */
7993                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7994                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7995                         LOGE("failed to set attribute");
7996                         return MM_ERROR_PLAYER_INTERNAL;
7997                 }
7998         } else {
7999                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8000                 /* check filepath */
8001                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8002
8003                 if (!__mmplayer_check_subtitle(player)) {
8004                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8005                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8006                                 LOGE("failed to set attribute");
8007                                 return MM_ERROR_PLAYER_INTERNAL;
8008                         }
8009
8010                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8011                                 LOGE("fail to create text pipeline");
8012                                 return MM_ERROR_PLAYER_INTERNAL;
8013                         }
8014
8015                         result = _mmplayer_sync_subtitle_pipeline(player);
8016                 } else {
8017                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8018                 }
8019
8020                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8021                 player->is_external_subtitle_added_now = TRUE;
8022
8023                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8024                 if (!player->subtitle_language_list) {
8025                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8026                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8027                                 LOGW("subtitle language list is not updated yet");
8028                 }
8029                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8030         }
8031
8032         MMPLAYER_FLEAVE();
8033         return result;
8034 }
8035
8036 static int
8037 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8038 {
8039         int result = MM_ERROR_NONE;
8040         gchar *change_pad_name = NULL;
8041         GstPad *sinkpad = NULL;
8042         mmplayer_gst_element_t *mainbin = NULL;
8043         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8044         GstCaps *caps = NULL;
8045         gint total_track_num = 0;
8046
8047         MMPLAYER_FENTER();
8048
8049         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8050                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8051
8052         LOGD("Change Track(%d) to %d", type, index);
8053
8054         mainbin = player->pipeline->mainbin;
8055
8056         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8057                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8058         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8059                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8060         } else {
8061                 /* Changing Video Track is not supported. */
8062                 LOGE("Track Type Error");
8063                 goto EXIT;
8064         }
8065
8066         if (mainbin[elem_idx].gst == NULL) {
8067                 result = MM_ERROR_PLAYER_NO_OP;
8068                 LOGD("Req track doesn't exist");
8069                 goto EXIT;
8070         }
8071
8072         total_track_num = player->selector[type].total_track_num;
8073         if (total_track_num <= 0) {
8074                 result = MM_ERROR_PLAYER_NO_OP;
8075                 LOGD("Language list is not available");
8076                 goto EXIT;
8077         }
8078
8079         if ((index < 0) || (index >= total_track_num)) {
8080                 result = MM_ERROR_INVALID_ARGUMENT;
8081                 LOGD("Not a proper index : %d", index);
8082                 goto EXIT;
8083         }
8084
8085         /*To get the new pad from the selector*/
8086         change_pad_name = g_strdup_printf("sink_%u", index);
8087         if (change_pad_name == NULL) {
8088                 result = MM_ERROR_PLAYER_INTERNAL;
8089                 LOGD("Pad does not exists");
8090                 goto EXIT;
8091         }
8092
8093         LOGD("new active pad name: %s", change_pad_name);
8094
8095         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8096         if (sinkpad == NULL) {
8097                 LOGD("sinkpad is NULL");
8098                 result = MM_ERROR_PLAYER_INTERNAL;
8099                 goto EXIT;
8100         }
8101
8102         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8103         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8104
8105         caps = gst_pad_get_current_caps(sinkpad);
8106         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8107
8108         if (sinkpad)
8109                 gst_object_unref(sinkpad);
8110
8111         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8112                 __mmplayer_set_audio_attrs(player, caps);
8113
8114 EXIT:
8115         MMPLAYER_FREEIF(change_pad_name);
8116         return result;
8117 }
8118
8119 int
8120 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8121 {
8122         int result = MM_ERROR_NONE;
8123         mmplayer_t *player = NULL;
8124         mmplayer_gst_element_t *mainbin = NULL;
8125
8126         gint current_active_index = 0;
8127
8128         GstState current_state = GST_STATE_VOID_PENDING;
8129         GstEvent *event = NULL;
8130         gint64 time = 0;
8131
8132         MMPLAYER_FENTER();
8133
8134         player = (mmplayer_t *)hplayer;
8135         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8136
8137         if (!player->pipeline) {
8138                 LOGE("Track %d pre setting -> %d", type, index);
8139
8140                 player->selector[type].active_pad_index = index;
8141                 goto EXIT;
8142         }
8143
8144         mainbin = player->pipeline->mainbin;
8145
8146         current_active_index = player->selector[type].active_pad_index;
8147
8148         /*If index is same as running index no need to change the pad*/
8149         if (current_active_index == index)
8150                 goto EXIT;
8151
8152         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8153                 result = MM_ERROR_PLAYER_INVALID_STATE;
8154                 goto EXIT;
8155         }
8156
8157         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8158         if (current_state < GST_STATE_PAUSED) {
8159                 result = MM_ERROR_PLAYER_INVALID_STATE;
8160                 LOGW("Pipeline not in porper state");
8161                 goto EXIT;
8162         }
8163
8164         result = __mmplayer_change_selector_pad(player, type, index);
8165         if (result != MM_ERROR_NONE) {
8166                 LOGE("change selector pad error");
8167                 goto EXIT;
8168         }
8169
8170         player->selector[type].active_pad_index = index;
8171
8172         if (current_state == GST_STATE_PLAYING) {
8173                 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8174                         (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8175                         GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8176                 if (event) {
8177                         _mmplayer_gst_send_event_to_sink(player, event);
8178                 } else {
8179                         result = MM_ERROR_PLAYER_INTERNAL;
8180                         goto EXIT;
8181                 }
8182         }
8183
8184 EXIT:
8185         return result;
8186 }
8187
8188 int
8189 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8190 {
8191         mmplayer_t *player = (mmplayer_t *)hplayer;
8192
8193         MMPLAYER_FENTER();
8194
8195         /* check player handle */
8196         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8197
8198         *silent = player->set_mode.subtitle_off;
8199
8200         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8201
8202         MMPLAYER_FLEAVE();
8203
8204         return MM_ERROR_NONE;
8205 }
8206
8207 static gboolean
8208 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8209 {
8210         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8211         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8212
8213         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8214         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8215
8216         int idx = 0;
8217
8218         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8219                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8220                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8221                         mmplayer_dump_t *dump_s;
8222                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8223                         if (dump_s == NULL) {
8224                                 LOGE("malloc fail");
8225                                 return FALSE;
8226                         }
8227
8228                         dump_s->dump_element_file = NULL;
8229                         dump_s->dump_pad = NULL;
8230                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8231
8232                         if (dump_s->dump_pad) {
8233                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8234                                 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]);
8235                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8236                                 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);
8237                                 /* add list for removed buffer probe and close FILE */
8238                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8239                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8240                                 return TRUE;
8241                         } else {
8242                                 MMPLAYER_FREEIF(dump_s);
8243                                 LOGE("failed to get %s sink pad added", factory_name);
8244                         }
8245                 }
8246         }
8247         return FALSE;
8248 }
8249
8250 static GstPadProbeReturn
8251 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8252 {
8253         FILE *dump_data = (FILE *)u_data;
8254 //      int written = 0;
8255         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8256         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8257
8258         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8259
8260         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8261 #ifdef __DEBUG__
8262         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8263 #endif
8264         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8265
8266         gst_buffer_unmap(buffer, &probe_info);
8267
8268         return GST_PAD_PROBE_OK;
8269 }
8270
8271 static void
8272 __mmplayer_release_dump_list(GList *dump_list)
8273 {
8274         GList *d_list = dump_list;
8275
8276         if (!d_list)
8277                 return;
8278
8279         for (; d_list; d_list = g_list_next(d_list)) {
8280                 mmplayer_dump_t *dump_s = d_list->data;
8281                 if (dump_s->dump_pad) {
8282                         if (dump_s->probe_handle_id)
8283                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8284                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8285                 }
8286                 if (dump_s->dump_element_file) {
8287                         fclose(dump_s->dump_element_file);
8288                         dump_s->dump_element_file = NULL;
8289                 }
8290                 MMPLAYER_FREEIF(dump_s);
8291         }
8292         g_list_free(dump_list);
8293         dump_list = NULL;
8294 }
8295
8296 int
8297 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8298 {
8299         mmplayer_t *player = (mmplayer_t *)hplayer;
8300
8301         MMPLAYER_FENTER();
8302
8303         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8304         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8305
8306         *exist = (bool)player->has_closed_caption;
8307
8308         MMPLAYER_FLEAVE();
8309
8310         return MM_ERROR_NONE;
8311 }
8312
8313 void
8314 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8315 {
8316         MMPLAYER_FENTER();
8317         if (buffer) {
8318 #ifdef __DEBUG__
8319                 LOGD("unref internal gst buffer %p", buffer);
8320 #endif
8321                 gst_buffer_unref((GstBuffer *)buffer);
8322                 buffer = NULL;
8323         }
8324         MMPLAYER_FLEAVE();
8325 }
8326
8327 int
8328 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8329 {
8330         mmplayer_t *player = (mmplayer_t *)hplayer;
8331
8332         MMPLAYER_FENTER();
8333
8334         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8335         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8336
8337         if (MMPLAYER_IS_STREAMING(player))
8338                 *timeout = (int)player->ini.live_state_change_timeout;
8339         else
8340                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8341
8342         LOGD("timeout = %d", *timeout);
8343
8344         MMPLAYER_FLEAVE();
8345         return MM_ERROR_NONE;
8346 }
8347
8348 static void
8349 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8350 {
8351         int i = 0;
8352         MMPLAYER_FENTER();
8353         MMPLAYER_RETURN_IF_FAIL(player);
8354
8355         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8356
8357                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8358                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8359                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8360                         player->storage_info[i].id = -1;
8361                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8362
8363                         if (path_type != MMPLAYER_PATH_MAX)
8364                                 break;
8365                 }
8366         }
8367
8368         MMPLAYER_FLEAVE();
8369 }
8370
8371 int
8372 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8373 {
8374         int ret = MM_ERROR_NONE;
8375         mmplayer_t *player = (mmplayer_t *)hplayer;
8376         MMMessageParamType msg_param = {0, };
8377
8378         MMPLAYER_FENTER();
8379         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8380
8381         LOGW("state changed storage %d:%d", id, state);
8382
8383         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8384                 return MM_ERROR_NONE;
8385
8386         /* FIXME: text path should be handled seperately. */
8387         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8388                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8389                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8390                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8391                 LOGW("external storage is removed");
8392
8393                 if (player->msg_posted == FALSE) {
8394                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8395                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8396                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8397                         player->msg_posted = TRUE;
8398                 }
8399
8400                 /* unrealize the player */
8401                 ret = _mmplayer_unrealize(hplayer);
8402                 if (ret != MM_ERROR_NONE)
8403                         LOGE("failed to unrealize");
8404         }
8405
8406         MMPLAYER_FLEAVE();
8407         return ret;
8408 }
8409
8410 int
8411 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8412 {
8413         int ret = MM_ERROR_NONE;
8414         mmplayer_t *player = (mmplayer_t *)hplayer;
8415         int idx = 0, total = 0;
8416         gchar *result = NULL, *tmp = NULL;
8417
8418         MMPLAYER_FENTER();
8419         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8420         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8421
8422         total = *num = g_list_length(player->adaptive_info.var_list);
8423         if (total <= 0) {
8424                 LOGW("There is no stream variant info.");
8425                 return ret;
8426         }
8427
8428         result = g_strdup("");
8429         for (idx = 0 ; idx < total ; idx++) {
8430                 stream_variant_t *v_data = NULL;
8431                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8432
8433                 if (v_data) {
8434                         gchar data[64] = {0};
8435                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8436
8437                         tmp = g_strconcat(result, data, NULL);
8438                         g_free(result);
8439                         result = tmp;
8440                 } else {
8441                         LOGW("There is no variant data in %d", idx);
8442                         (*num)--;
8443                 }
8444         }
8445
8446         *var_info = (char *)result;
8447
8448         LOGD("variant info %d:%s", *num, *var_info);
8449         MMPLAYER_FLEAVE();
8450         return ret;
8451 }
8452
8453 int
8454 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8455 {
8456         int ret = MM_ERROR_NONE;
8457         mmplayer_t *player = (mmplayer_t *)hplayer;
8458
8459         MMPLAYER_FENTER();
8460         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8461
8462         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8463
8464         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8465         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8466         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8467
8468         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8469                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8470                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8471                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8472
8473                 /* FIXME: seek to current position for applying new variant limitation */
8474         }
8475
8476         MMPLAYER_FLEAVE();
8477         return ret;
8478
8479 }
8480
8481 int
8482 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8483 {
8484         int ret = MM_ERROR_NONE;
8485         mmplayer_t *player = (mmplayer_t *)hplayer;
8486
8487         MMPLAYER_FENTER();
8488         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8489         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8490
8491         *bandwidth = player->adaptive_info.limit.bandwidth;
8492         *width = player->adaptive_info.limit.width;
8493         *height = player->adaptive_info.limit.height;
8494
8495         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8496
8497         MMPLAYER_FLEAVE();
8498         return ret;
8499 }
8500
8501 int
8502 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8503 {
8504         int ret = MM_ERROR_NONE;
8505         mmplayer_t *player = (mmplayer_t *)hplayer;
8506
8507         MMPLAYER_FENTER();
8508         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8509         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8510         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8511
8512         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8513
8514         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8515                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8516         else /* live case */
8517                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8518
8519         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8520
8521         MMPLAYER_FLEAVE();
8522         return ret;
8523 }
8524
8525 int
8526 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8527 {
8528 #define IDX_FIRST_SW_CODEC 0
8529         mmplayer_t *player = (mmplayer_t *)hplayer;
8530         const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8531
8532         MMPLAYER_FENTER();
8533         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8534
8535         LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8536                 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8537                 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8538
8539         switch (stream_type) {
8540         case MM_PLAYER_STREAM_TYPE_AUDIO:
8541         /* to support audio codec selection, codec info have to be added in ini file as below.
8542            audio codec element hw = xxxx
8543            audio codec element sw = avdec */
8544                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8545                          (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8546                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8547                          (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8548                         LOGE("There is no audio codec info for codec_type %d", codec_type);
8549                         return MM_ERROR_PLAYER_NO_OP;
8550                 }
8551         break;
8552         case MM_PLAYER_STREAM_TYPE_VIDEO:
8553         /* to support video codec selection, codec info have to be added in ini file as below.
8554            video codec element hw = omx
8555            video codec element sw = avdec */
8556                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8557                          (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8558                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8559                          (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8560                         LOGE("There is no video codec info for codec_type %d", codec_type);
8561                         return MM_ERROR_PLAYER_NO_OP;
8562                 }
8563         break;
8564         default:
8565                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8566                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8567         break;
8568         }
8569
8570         LOGD("update %s codec_type to %d", attr_name, codec_type);
8571         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8572
8573         MMPLAYER_FLEAVE();
8574         return MM_ERROR_NONE;
8575 }
8576
8577 int
8578 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8579 {
8580         mmplayer_t *player = (mmplayer_t *)hplayer;
8581         GstElement *rg_vol_element = NULL;
8582
8583         MMPLAYER_FENTER();
8584
8585         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8586
8587         player->sound.rg_enable = enabled;
8588
8589         /* just hold rgvolume enable value if pipeline is not ready */
8590         if (!player->pipeline || !player->pipeline->audiobin) {
8591                 LOGD("pipeline is not ready. holding rgvolume enable value");
8592                 return MM_ERROR_NONE;
8593         }
8594
8595         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8596
8597         if (!rg_vol_element) {
8598                 LOGD("rgvolume element is not created");
8599                 return MM_ERROR_PLAYER_INTERNAL;
8600         }
8601
8602         if (enabled)
8603                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8604         else
8605                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8606
8607         MMPLAYER_FLEAVE();
8608
8609         return MM_ERROR_NONE;
8610 }
8611
8612 int
8613 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8614 {
8615         mmplayer_t *player = (mmplayer_t *)hplayer;
8616         GstElement *rg_vol_element = NULL;
8617         gboolean enable = FALSE;
8618
8619         MMPLAYER_FENTER();
8620
8621         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8622         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8623
8624         /* just hold enable_rg value if pipeline is not ready */
8625         if (!player->pipeline || !player->pipeline->audiobin) {
8626                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8627                 *enabled = player->sound.rg_enable;
8628                 return MM_ERROR_NONE;
8629         }
8630
8631         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8632
8633         if (!rg_vol_element) {
8634                 LOGD("rgvolume element is not created");
8635                 return MM_ERROR_PLAYER_INTERNAL;
8636         }
8637
8638         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8639         *enabled = (bool)enable;
8640
8641         MMPLAYER_FLEAVE();
8642
8643         return MM_ERROR_NONE;
8644 }
8645
8646 int
8647 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8648 {
8649         mmplayer_t *player = (mmplayer_t *)hplayer;
8650         MMHandleType attrs = 0;
8651         int handle = 0;
8652         int ret = MM_ERROR_NONE;
8653
8654         MMPLAYER_FENTER();
8655
8656         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8657
8658         attrs = MMPLAYER_GET_ATTRS(player);
8659         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8660
8661         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8662         if (!handle) {
8663                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8664                 return MM_ERROR_PLAYER_INTERNAL;
8665         }
8666
8667         player->video_roi.scale_x = scale_x;
8668         player->video_roi.scale_y = scale_y;
8669         player->video_roi.scale_width = scale_width;
8670         player->video_roi.scale_height = scale_height;
8671
8672         /* check video sinkbin is created */
8673         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8674                 return MM_ERROR_NONE;
8675
8676         if (!gst_video_overlay_set_video_roi_area(
8677                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8678                 scale_x, scale_y, scale_width, scale_height))
8679                 ret = MM_ERROR_PLAYER_INTERNAL;
8680         else
8681                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8682                         scale_x, scale_y, scale_width, scale_height);
8683
8684         MMPLAYER_FLEAVE();
8685
8686         return ret;
8687 }
8688
8689 int
8690 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8691 {
8692         mmplayer_t *player = (mmplayer_t *)hplayer;
8693         int ret = MM_ERROR_NONE;
8694
8695         MMPLAYER_FENTER();
8696
8697         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8698         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8699
8700         *scale_x = player->video_roi.scale_x;
8701         *scale_y = player->video_roi.scale_y;
8702         *scale_width = player->video_roi.scale_width;
8703         *scale_height = player->video_roi.scale_height;
8704
8705         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8706                 *scale_x, *scale_y, *scale_width, *scale_height);
8707
8708         return ret;
8709 }
8710
8711 int
8712 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8713 {
8714         mmplayer_t* player = (mmplayer_t*)hplayer;
8715
8716         MMPLAYER_FENTER();
8717
8718         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8719
8720         player->client_pid = pid;
8721
8722         LOGD("client pid[%d] %p", pid, player);
8723
8724         MMPLAYER_FLEAVE();
8725
8726         return MM_ERROR_NONE;
8727 }
8728
8729 static gboolean
8730 __mmplayer_update_duration_value(mmplayer_t *player)
8731 {
8732         gboolean ret = FALSE;
8733         gint64 dur_nsec = 0;
8734         LOGD("try to update duration");
8735
8736         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8737                 player->duration = dur_nsec;
8738                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8739                 ret = TRUE;
8740         }
8741
8742         if (player->duration < 0) {
8743                 LOGW("duration is Non-Initialized !!!");
8744                 player->duration = 0;
8745         }
8746
8747         /* update streaming service type */
8748         player->streaming_type =  _mmplayer_get_stream_service_type(player);
8749
8750         /* check duration is OK */
8751         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8752                 /* FIXIT : find another way to get duration here. */
8753                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8754
8755         return ret;
8756 }
8757
8758 static gboolean
8759 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8760 {
8761         /* update audio params
8762         NOTE : We need original audio params and it can be only obtained from src pad of audio
8763         decoder. Below code only valid when we are not using 'resampler' just before
8764         'audioconverter'. */
8765         GstCaps *caps_a = NULL;
8766         GstPad *pad = NULL;
8767         gint samplerate = 0, channels = 0;
8768         GstStructure *p = NULL;
8769         GstElement *aconv = NULL;
8770
8771         LOGD("try to update audio attrs");
8772
8773         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8774
8775         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8776                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8777         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8778                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8779         } else {
8780                 LOGE("there is no audio converter");
8781                 return FALSE;
8782         }
8783
8784         pad = gst_element_get_static_pad(aconv, "sink");
8785
8786         if (!pad) {
8787                 LOGW("failed to get pad from audio converter");
8788                 return FALSE;
8789         }
8790
8791         caps_a = gst_pad_get_current_caps(pad);
8792         if (!caps_a) {
8793                 LOGW("not ready to get audio caps");
8794                 gst_object_unref(pad);
8795                 return FALSE;
8796         }
8797
8798         p = gst_caps_get_structure(caps_a, 0);
8799
8800         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8801
8802         gst_structure_get_int(p, "rate", &samplerate);
8803         gst_structure_get_int(p, "channels", &channels);
8804
8805         mm_player_set_attribute((MMHandleType)player, NULL,
8806                         "content_audio_samplerate", samplerate,
8807                         "content_audio_channels", channels, NULL);
8808
8809         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
8810
8811         gst_caps_unref(caps_a);
8812         gst_object_unref(pad);
8813
8814         return TRUE;
8815 }
8816
8817 static gboolean
8818 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8819 {
8820         LOGD("try to update video attrs");
8821
8822         GstCaps *caps_v = NULL;
8823         GstPad *pad = NULL;
8824         gint tmpNu, tmpDe;
8825         gint width, height;
8826         GstStructure *p = NULL;
8827
8828         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8829         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8830
8831         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8832         if (!pad) {
8833                 LOGD("no videosink sink pad");
8834                 return FALSE;
8835         }
8836
8837         caps_v = gst_pad_get_current_caps(pad);
8838         /* Use v_stream_caps, if fail to get video_sink sink pad*/
8839         if (!caps_v && player->v_stream_caps) {
8840                 caps_v = player->v_stream_caps;
8841                 gst_caps_ref(caps_v);
8842         }
8843
8844         if (!caps_v) {
8845                 LOGD("no negitiated caps from videosink");
8846                 gst_object_unref(pad);
8847                 return FALSE;
8848         }
8849
8850         p = gst_caps_get_structure(caps_v, 0);
8851         gst_structure_get_int(p, "width", &width);
8852         gst_structure_get_int(p, "height", &height);
8853
8854         mm_player_set_attribute((MMHandleType)player, NULL,
8855                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8856
8857         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8858
8859         SECURE_LOGD("width : %d     height : %d", width, height);
8860
8861         gst_caps_unref(caps_v);
8862         gst_object_unref(pad);
8863
8864         if (tmpDe > 0) {
8865                 mm_player_set_attribute((MMHandleType)player, NULL,
8866                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8867                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8868         }
8869
8870         return TRUE;
8871 }
8872
8873 static gboolean
8874 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8875 {
8876         gboolean ret = FALSE;
8877         guint64 data_size = 0;
8878         gchar *path = NULL;
8879         struct stat sb;
8880
8881         /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8882         if (!player->duration)
8883                 return FALSE;
8884
8885         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8886                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8887                 if (stat(path, &sb) == 0)
8888                         data_size = (guint64)sb.st_size;
8889
8890         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8891                 data_size = player->http_content_size;
8892         }
8893
8894         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8895
8896         if (data_size) {
8897                 guint64 bitrate = 0;
8898                 guint64 msec_dur = 0;
8899
8900                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8901                 if (msec_dur > 0) {
8902                         bitrate = data_size * 8 * 1000 / msec_dur;
8903                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8904                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8905                         mm_player_set_attribute((MMHandleType)player, NULL,
8906                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8907                         ret = TRUE;
8908                 } else {
8909                         LOGD("player duration is less than 0");
8910                 }
8911         }
8912
8913         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8914                 if (player->total_bitrate) {
8915                         mm_player_set_attribute((MMHandleType)player, NULL,
8916                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8917                         ret = TRUE;
8918                 }
8919         }
8920
8921         return ret;
8922 }
8923
8924 static void
8925 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8926 {
8927         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8928         data->uri_type = uri_type;
8929 }
8930
8931 static int
8932 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8933 {
8934         int ret = MM_ERROR_PLAYER_INVALID_URI;
8935         int mem_size = 0;
8936         char *buffer = NULL;
8937         char *seperator = strchr(path, ',');
8938         char ext[100] = {0,}, size[100] = {0,};
8939
8940         if (seperator) {
8941                 if ((buffer = strstr(path, "ext="))) {
8942                         buffer += strlen("ext=");
8943
8944                         if (strlen(buffer)) {
8945                                 strncpy(ext, buffer, 99);
8946
8947                                 if ((seperator = strchr(ext, ','))
8948                                         || (seperator = strchr(ext, ' '))
8949                                         || (seperator = strchr(ext, '\0'))) {
8950                                         seperator[0] = '\0';
8951                                 }
8952                         }
8953                 }
8954
8955                 if ((buffer = strstr(path, "size="))) {
8956                         buffer += strlen("size=");
8957
8958                         if (strlen(buffer) > 0) {
8959                                 strncpy(size, buffer, 99);
8960
8961                                 if ((seperator = strchr(size, ','))
8962                                         || (seperator = strchr(size, ' '))
8963                                         || (seperator = strchr(size, '\0'))) {
8964                                         seperator[0] = '\0';
8965                                 }
8966
8967                                 mem_size = atoi(size);
8968                         }
8969                 }
8970         }
8971
8972         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8973
8974         if (mem_size && param) {
8975                 if (data->input_mem.buf)
8976                         free(data->input_mem.buf);
8977                 data->input_mem.buf = malloc(mem_size);
8978
8979                 if (data->input_mem.buf) {
8980                         memcpy(data->input_mem.buf, param, mem_size);
8981                         data->input_mem.len = mem_size;
8982                         ret = MM_ERROR_NONE;
8983                 } else {
8984                         LOGE("failed to alloc mem %d", mem_size);
8985                         ret = MM_ERROR_PLAYER_INTERNAL;
8986                 }
8987
8988                 data->input_mem.offset = 0;
8989                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8990         }
8991
8992         return ret;
8993 }
8994
8995 static int
8996 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8997 {
8998         gchar *location = NULL;
8999         GError *err = NULL;
9000         char *path = NULL;
9001         int ret = MM_ERROR_NONE;
9002
9003         if ((path = strstr(uri, "file://"))) {
9004                 location = g_filename_from_uri(uri, NULL, &err);
9005                 if (!location || (err != NULL)) {
9006                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9007                                 (err != NULL) ? err->message : "unknown error");
9008                         if (err)
9009                                 g_error_free(err);
9010
9011                         MMPLAYER_FREEIF(location);
9012
9013                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9014                         return MM_ERROR_PLAYER_INVALID_URI;
9015                 }
9016                 LOGD("path from uri: %s", location);
9017         }
9018
9019         path = (location != NULL) ? (location) : ((char *)uri);
9020
9021
9022         ret = _mmplayer_exist_file_path(path);
9023
9024         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9025         if (ret == MM_ERROR_NONE) {
9026                 g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9027                 if (_mmplayer_is_sdp_file(path)) {
9028                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9029                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9030                 } else {
9031                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9032                 }
9033         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9034                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9035         } else {
9036                 LOGE("invalid uri, could not play..");
9037                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9038         }
9039
9040         MMPLAYER_FREEIF(location);
9041
9042         return ret;
9043 }
9044
9045 static mmplayer_video_decoded_data_info_t *
9046 __mmplayer_create_stream_from_pad(GstPad *pad)
9047 {
9048         GstCaps *caps = NULL;
9049         GstStructure *structure = NULL;
9050         unsigned int fourcc = 0;
9051         const gchar *string_format = NULL;
9052         mmplayer_video_decoded_data_info_t *stream = NULL;
9053         gint width, height;
9054         MMPixelFormatType format;
9055         GstVideoInfo info;
9056
9057         caps = gst_pad_get_current_caps(pad);
9058         if (!caps) {
9059                 LOGE("Caps is NULL.");
9060                 return NULL;
9061         }
9062
9063 #ifdef __DEBUG__
9064         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9065 #endif
9066         structure = gst_caps_get_structure(caps, 0);
9067         gst_structure_get_int(structure, "width", &width);
9068         gst_structure_get_int(structure, "height", &height);
9069         string_format = gst_structure_get_string(structure, "format");
9070
9071         if (string_format)
9072                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9073         format = _mmplayer_get_pixtype(fourcc);
9074         gst_video_info_from_caps(&info, caps);
9075         gst_caps_unref(caps);
9076
9077         /* moved here */
9078         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9079                 LOGE("Wrong condition!!");
9080                 return NULL;
9081         }
9082
9083         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9084         if (!stream) {
9085                 LOGE("failed to alloc mem for video data");
9086                 return NULL;
9087         }
9088
9089         stream->width = width;
9090         stream->height = height;
9091         stream->format = format;
9092         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9093
9094         return stream;
9095 }
9096
9097 static void
9098 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9099 {
9100         unsigned int pitch = 0;
9101         unsigned int size = 0;
9102         int index = 0;
9103         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9104         tbm_bo bo = NULL;
9105
9106         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9107                 bo = gst_tizen_memory_get_bos(mem, index);
9108                 if (bo)
9109                         stream->bo[index] = tbm_bo_ref(bo);
9110                 else
9111                         LOGE("failed to get bo for index %d", index);
9112         }
9113
9114         for (index = 0; index < stream->plane_num; index++) {
9115                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9116                 stream->stride[index] = pitch;
9117                 if (pitch)
9118                         stream->elevation[index] = size / pitch;
9119                 else
9120                         stream->elevation[index] = stream->height;
9121         }
9122 }
9123
9124 static gboolean
9125 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9126 {
9127         if (stream->format == MM_PIXEL_FORMAT_I420) {
9128                 int ret = TBM_SURFACE_ERROR_NONE;
9129                 tbm_surface_h surface;
9130                 tbm_surface_info_s info;
9131
9132                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9133
9134                 ret = tbm_surface_get_info(surface, &info);
9135                 if (ret != TBM_SURFACE_ERROR_NONE) {
9136                         tbm_surface_destroy(surface);
9137                         return FALSE;
9138                 }
9139
9140                 tbm_surface_destroy(surface);
9141                 stream->stride[0] = info.planes[0].stride;
9142                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9143                 stream->stride[1] = info.planes[1].stride;
9144                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9145                 stream->stride[2] = info.planes[2].stride;
9146                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9147                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9148         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9149                 stream->stride[0] = stream->width * 4;
9150                 stream->elevation[0] = stream->height;
9151                 stream->bo_size = stream->stride[0] * stream->height;
9152         } else {
9153                 LOGE("Not support format %d", stream->format);
9154                 return FALSE;
9155         }
9156
9157         return TRUE;
9158 }
9159
9160 static gboolean
9161 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9162 {
9163         tbm_bo_handle thandle;
9164         gboolean is_mapped;
9165         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9166         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9167         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9168         int i = 0;
9169         int j = 0;
9170         int k = 0;
9171         unsigned char *src = NULL;
9172         unsigned char *dest = NULL;
9173         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9174
9175         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9176         if (!is_mapped) {
9177                 LOGE("fail to gst_memory_map");
9178                 return FALSE;
9179         }
9180
9181         if (!mapinfo.data) {
9182                 LOGE("data pointer is wrong");
9183                 goto ERROR;
9184         }
9185
9186         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9187         if (!stream->bo[0]) {
9188                 LOGE("Fail to tbm_bo_alloc!!");
9189                 goto ERROR;
9190         }
9191
9192         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9193         if (!thandle.ptr) {
9194                 LOGE("thandle pointer is wrong");
9195                 goto ERROR;
9196         }
9197
9198         if (stream->format == MM_PIXEL_FORMAT_I420) {
9199                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9200                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9201                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9202                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9203
9204                 dest_offset[0] = 0;
9205                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9206                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9207
9208                 for (i = 0; i < 3; i++) {
9209                         src = mapinfo.data + src_offset[i];
9210                         dest = thandle.ptr + dest_offset[i];
9211
9212                         if (i > 0)
9213                                 k = 1;
9214
9215                         for (j = 0; j < stream->height >> k; j++) {
9216                                 memcpy(dest, src, stream->width>>k);
9217                                 src += src_stride[i];
9218                                 dest += stream->stride[i];
9219                         }
9220                 }
9221         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9222                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9223         } else {
9224                 LOGE("Not support format %d", stream->format);
9225                 goto ERROR;
9226         }
9227
9228         tbm_bo_unmap(stream->bo[0]);
9229         gst_memory_unmap(mem, &mapinfo);
9230
9231         return TRUE;
9232
9233 ERROR:
9234         if (stream->bo[0])
9235                 tbm_bo_unmap(stream->bo[0]);
9236
9237         if (is_mapped)
9238                 gst_memory_unmap(mem, &mapinfo);
9239
9240         return FALSE;
9241 }
9242
9243 static void
9244 __mmplayer_set_pause_state(mmplayer_t *player)
9245 {
9246         if (player->sent_bos)
9247                 return;
9248
9249         /* rtsp case, get content attrs by GstMessage */
9250         if (MMPLAYER_IS_RTSP_STREAMING(player))
9251                 return;
9252
9253         /* it's first time to update all content attrs. */
9254         _mmplayer_update_content_attrs(player, ATTR_ALL);
9255 }
9256
9257 static void
9258 __mmplayer_set_playing_state(mmplayer_t *player)
9259 {
9260         gchar *audio_codec = NULL;
9261
9262         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9263                 /* initialize because auto resume is done well. */
9264                 player->resumed_by_rewind = FALSE;
9265                 player->playback_rate = 1.0;
9266         }
9267
9268         if (player->sent_bos)
9269                 return;
9270
9271         /* try to get content metadata */
9272
9273         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9274          * c-api since c-api doesn't use _start() anymore. It may not work propery with
9275          * legacy mmfw-player api
9276          */
9277         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9278
9279         if ((player->cmd == MMPLAYER_COMMAND_START)
9280                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9281                 __mmplayer_handle_missed_plugin(player);
9282         }
9283
9284         /* check audio codec field is set or not
9285          * we can get it from typefinder or codec's caps.
9286          */
9287         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9288
9289         /* The codec format can't be sent for audio only case like amr, mid etc.
9290          * Because, parser don't make related TAG.
9291          * So, if it's not set yet, fill it with found data.
9292          */
9293         if (!audio_codec) {
9294                 if (g_strrstr(player->type, "audio/midi"))
9295                         audio_codec = "MIDI";
9296                 else if (g_strrstr(player->type, "audio/x-amr"))
9297                         audio_codec = "AMR";
9298                 else if (g_strrstr(player->type, "audio/mpeg")
9299                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9300                         audio_codec = "AAC";
9301                 else
9302                         audio_codec = "unknown";
9303
9304                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9305                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9306                         LOGE("failed to set attribute");
9307
9308                 LOGD("set audio codec type with caps");
9309         }
9310
9311         return;
9312 }