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