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