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