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