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