[0.6.249] Post INTERRUPT_STARTED message before _mmplayer_unrealize
[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
3277         /* check DRC, if it is, destroy the prev bo list to create again */
3278         if (player->video_bo_size != size) {
3279                 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3280                 __mmplayer_video_stream_destroy_bo_list(player);
3281                 player->video_bo_size = size;
3282         }
3283
3284         MMPLAYER_VIDEO_BO_LOCK(player);
3285
3286         if ((!player->video_bo_list) ||
3287                 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3288
3289                 /* create bo list */
3290                 int idx = 0;
3291                 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3292
3293                 if (player->video_bo_list) {
3294                         /* if bo list did not created all, try it again. */
3295                         idx = g_list_length(player->video_bo_list);
3296                         LOGD("bo list exist(len: %d)", idx);
3297                 }
3298
3299                 for (; idx < player->ini.num_of_video_bo; idx++) {
3300                         mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3301                         if (!bo_info) {
3302                                 LOGE("Fail to alloc bo_info.");
3303                                 break;
3304                         }
3305                         bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3306                         if (!bo_info->bo) {
3307                                 LOGE("Fail to tbm_bo_alloc.");
3308                                 MMPLAYER_FREEIF(bo_info);
3309                                 break;
3310                         }
3311                         bo_info->used = FALSE;
3312                         player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3313                 }
3314
3315                 /* update video num buffers */
3316                 LOGD("video_num_buffers : %d", idx);
3317                 mm_player_set_attribute((MMHandleType)player, NULL,
3318                                 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3319                                 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3320                                 NULL);
3321
3322                 if (idx == 0) {
3323                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3324                         return NULL;
3325                 }
3326         }
3327
3328         while (TRUE) {
3329                 /* get bo from list*/
3330                 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3331                         mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3332                         if (tmp && (tmp->used == FALSE)) {
3333                                 LOGD("found bo %p to use", tmp->bo);
3334                                 tmp->used = TRUE;
3335                                 MMPLAYER_VIDEO_BO_UNLOCK(player);
3336                                 return tbm_bo_ref(tmp->bo);
3337                         }
3338                 }
3339                 if (!ret) {
3340                         LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3341                         MMPLAYER_VIDEO_BO_UNLOCK(player);
3342                         return NULL;
3343                 }
3344
3345                 if (player->ini.video_bo_timeout <= 0) {
3346                         MMPLAYER_VIDEO_BO_WAIT(player);
3347                 } else {
3348                         gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3349                         ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3350                 }
3351                 continue;
3352         }
3353 }
3354
3355 static void
3356 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3357 {
3358         mmplayer_t *player = (mmplayer_t *)data;
3359         MMPLAYER_FENTER();
3360         MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3361
3362         /* send prerolled pkt */
3363         player->video_stream_prerolled = false;
3364
3365         __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3366
3367         /* not to send prerolled pkt again */
3368         player->video_stream_prerolled = true;
3369 }
3370
3371 static void
3372 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3373 {
3374         mmplayer_t *player = (mmplayer_t *)data;
3375         mmplayer_video_decoded_data_info_t *stream = NULL;
3376         GstMemory *mem = NULL;
3377
3378         MMPLAYER_FENTER();
3379         MMPLAYER_RETURN_IF_FAIL(player);
3380         MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3381
3382         if (player->video_stream_prerolled) {
3383                 player->video_stream_prerolled = false;
3384                 LOGD("skip the prerolled pkt not to send it again");
3385                 return;
3386         }
3387
3388         /* clear stream data structure */
3389         stream = __mmplayer_create_stream_from_pad(pad);
3390         if (!stream) {
3391                 LOGE("failed to alloc stream");
3392                 return;
3393         }
3394
3395         _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3396
3397         /* set size and timestamp */
3398         mem = gst_buffer_peek_memory(buffer, 0);
3399         stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3400         stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3401
3402         /* check zero-copy */
3403         if (player->set_mode.video_zc &&
3404                 player->set_mode.video_export &&
3405                 gst_is_tizen_memory(mem)) {
3406                 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3407                 stream->internal_buffer = gst_buffer_ref(buffer);
3408         } else { /* sw codec */
3409                 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3410                         goto ERROR;
3411
3412                 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3413                         goto ERROR;
3414         }
3415
3416         if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3417                 LOGE("failed to send video decoded data.");
3418                 goto ERROR;
3419         }
3420
3421         return;
3422
3423 ERROR:
3424         LOGE("release video stream resource.");
3425         if (gst_is_tizen_memory(mem)) {
3426                 int i = 0;
3427                 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3428                         if (stream->bo[i])
3429                                 tbm_bo_unref(stream->bo[i]);
3430                 }
3431
3432                 /* unref gst buffer */
3433                 if (stream->internal_buffer)
3434                         gst_buffer_unref(stream->internal_buffer);
3435         } else {
3436                 if (stream->bo[0])
3437                         _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3438         }
3439         MMPLAYER_FREEIF(stream);
3440         return;
3441 }
3442
3443 static void
3444 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3445 {
3446         mmplayer_gst_element_t *videobin = NULL;
3447
3448         MMPLAYER_FENTER();
3449         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3450
3451         videobin = player->pipeline->videobin;
3452
3453         /* Set spatial media metadata and/or user settings to the element.
3454          * */
3455         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3456                         "projection-type", player->video360_metadata.projection_type, NULL);
3457
3458         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3459                         "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3460
3461         if (player->video360_metadata.full_pano_width_pixels &&
3462                         player->video360_metadata.full_pano_height_pixels &&
3463                         player->video360_metadata.cropped_area_image_width &&
3464                         player->video360_metadata.cropped_area_image_height) {
3465                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3466                                 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3467                                 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3468                                                 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3469                                 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3470                                 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3471                                                 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3472                                 NULL);
3473         }
3474
3475         if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3476                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3477                                 "horizontal-fov", player->video360_horizontal_fov,
3478                                 "vertical-fov", player->video360_vertical_fov, NULL);
3479         }
3480
3481         if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3482                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3483                                 "zoom", 1.0f / player->video360_zoom, NULL);
3484         }
3485
3486         if (player->video360_yaw_radians <= M_PI &&
3487                         player->video360_yaw_radians >= -M_PI &&
3488                         player->video360_pitch_radians <= M_PI_2 &&
3489                         player->video360_pitch_radians >= -M_PI_2) {
3490                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3491                                 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3492                                 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3493         } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3494                 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3495                                 "pose-yaw", player->video360_metadata.init_view_heading,
3496                                 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3497         }
3498
3499         g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3500                         "passthrough", !player->is_video360_enabled, NULL);
3501
3502
3503         MMPLAYER_FLEAVE();
3504 }
3505
3506 static int
3507 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3508 {
3509         gchar *video_csc = "videoconvert"; /* default colorspace converter */
3510         GList *element_bucket = NULL;
3511
3512         MMPLAYER_FENTER();
3513         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3514
3515         /* create video360 filter */
3516         if (player->is_360_feature_enabled && player->is_content_spherical) {
3517                 LOGD("create video360 element");
3518                 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3519                 __mmplayer_gst_set_video360_property(player);
3520                 goto EXIT;
3521         }
3522
3523         if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3524                 LOGD("skip creating the videoconv and rotator");
3525                 return MM_ERROR_NONE;
3526         }
3527
3528         /* in case of sw codec & overlay surface type, except 360 playback.
3529          * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3530         LOGD("create video converter: %s", video_csc);
3531         MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3532
3533 EXIT:
3534         *bucket = element_bucket;
3535         MMPLAYER_FLEAVE();
3536         return MM_ERROR_NONE;
3537
3538 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3539         g_list_free(element_bucket);
3540
3541         *bucket = NULL;
3542         MMPLAYER_FLEAVE();
3543         return MM_ERROR_PLAYER_INTERNAL;
3544 }
3545
3546 static gchar *
3547 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3548 {
3549         gchar *factory_name = NULL;
3550
3551         switch (surface_type) {
3552         case MM_DISPLAY_SURFACE_OVERLAY:
3553                 if (strlen(player->ini.videosink_element_overlay) > 0)
3554                         factory_name = player->ini.videosink_element_overlay;
3555                 break;
3556         case MM_DISPLAY_SURFACE_REMOTE:
3557         case MM_DISPLAY_SURFACE_NULL:
3558                 if (strlen(player->ini.videosink_element_fake) > 0)
3559                         factory_name = player->ini.videosink_element_fake;
3560                 break;
3561         default:
3562                 LOGE("unidentified surface type");
3563                 break;
3564         }
3565
3566         LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3567         return factory_name;
3568 }
3569
3570 static int
3571 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3572 {
3573         gchar *factory_name = NULL;
3574         mmplayer_gst_element_t *videobin = NULL;
3575         MMHandleType attrs;
3576         int gapless = 0;
3577
3578         MMPLAYER_FENTER();
3579         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3580
3581         videobin = player->pipeline->videobin;
3582         factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3583
3584         attrs = MMPLAYER_GET_ATTRS(player);
3585         if (!attrs) {
3586                 LOGE("cannot get content attribute");
3587                 return MM_ERROR_PLAYER_INTERNAL;
3588         }
3589
3590         if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3591                 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3592                 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3593                         g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3594                                 "use-tbm", use_tbm, NULL);
3595                 }
3596
3597                 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3598                         return MM_ERROR_PLAYER_INTERNAL;
3599
3600                 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3601
3602         } else {
3603                 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3604                                                                                 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3605         }
3606
3607         mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3608         if (gapless > 0) {
3609                 LOGD("disable last-sample");
3610                 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3611         }
3612
3613         if (player->set_mode.video_export) {
3614                 int enable = 0;
3615                 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3616                 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3617                         g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3618
3619                 _mmplayer_add_signal_connection(player,
3620                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3621                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3622                                                                 "handoff",
3623                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3624                                                                 (gpointer)player);
3625
3626                 _mmplayer_add_signal_connection(player,
3627                                                                 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3628                                                                 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3629                                                                 "preroll-handoff",
3630                                                                 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3631                                                                 (gpointer)player);
3632         }
3633
3634         if (videobin[MMPLAYER_V_SINK].gst) {
3635                 GstPad *sink_pad = NULL;
3636                 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3637                 if (sink_pad) {
3638                         _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3639                                         "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3640                         gst_object_unref(GST_OBJECT(sink_pad));
3641                 } else {
3642                         LOGE("failed to get sink pad from videosink");
3643                 }
3644         }
3645
3646         return MM_ERROR_NONE;
3647 }
3648
3649 /**
3650  * VIDEO BIN
3651  * - video overlay surface(arm/x86) : tizenwlsink
3652  */
3653 static int
3654 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3655 {
3656         GstPad *pad = NULL;
3657         GList *element_bucket = NULL;
3658         mmplayer_gst_element_t *first_element = NULL;
3659         mmplayer_gst_element_t *videobin = NULL;
3660         gchar *videosink_factory_name = NULL;
3661
3662         MMPLAYER_FENTER();
3663         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3664
3665         /* alloc handles */
3666         videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3667         if (!videobin)
3668                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3669
3670         player->pipeline->videobin = videobin;
3671
3672         /* create bin */
3673         videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3674         videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3675         if (!videobin[MMPLAYER_V_BIN].gst) {
3676                 LOGE("failed to create videobin");
3677                 goto ERROR;
3678         }
3679
3680         if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3681                 goto ERROR;
3682
3683         videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3684         MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3685
3686         /* additional setting for sink plug-in */
3687         if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3688                 LOGE("failed to set video property");
3689                 goto ERROR;
3690         }
3691
3692         /* store it as it's sink element */
3693         __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3694
3695         /* adding created elements to bin */
3696         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3697                 LOGE("failed to add elements");
3698                 goto ERROR;
3699         }
3700
3701         /* Linking elements in the bucket by added order */
3702         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3703                 LOGE("failed to link elements");
3704                 goto ERROR;
3705         }
3706
3707         /* get first element's sinkpad for creating ghostpad */
3708         first_element = (mmplayer_gst_element_t *)element_bucket->data;
3709         if (!first_element) {
3710                 LOGE("failed to get first element from bucket");
3711                 goto ERROR;
3712         }
3713
3714         pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3715         if (!pad) {
3716                 LOGE("failed to get pad from first element");
3717                 goto ERROR;
3718         }
3719
3720         /* create ghostpad */
3721         player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3722         if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3723                 LOGE("failed to add ghostpad to videobin");
3724                 goto ERROR;
3725         }
3726         gst_object_unref(pad);
3727
3728         /* done. free allocated variables */
3729         g_list_free(element_bucket);
3730
3731         MMPLAYER_FLEAVE();
3732
3733         return MM_ERROR_NONE;
3734
3735 ERROR:
3736         LOGE("ERROR : releasing videobin");
3737         g_list_free(element_bucket);
3738
3739         if (pad)
3740                 gst_object_unref(GST_OBJECT(pad));
3741
3742         /* release videobin with it's children */
3743         if (videobin[MMPLAYER_V_BIN].gst)
3744                 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3745
3746         MMPLAYER_FREEIF(videobin);
3747         player->pipeline->videobin = NULL;
3748
3749         return MM_ERROR_PLAYER_INTERNAL;
3750 }
3751
3752 static int
3753 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3754 {
3755         GList *element_bucket = NULL;
3756         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3757
3758         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3759         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3760         g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3761                                                         "signal-handoffs", FALSE,
3762                                                         NULL);
3763
3764         MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3765         _mmplayer_add_signal_connection(player,
3766                                                         G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3767                                                         MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3768                                                         "handoff",
3769                                                         G_CALLBACK(__mmplayer_update_subtitle),
3770                                                         (gpointer)player);
3771
3772         g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3773                                                 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3774
3775         if (!player->play_subtitle) {
3776                 LOGD("add textbin sink as sink element of whole pipeline.");
3777                 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3778         }
3779
3780         /* adding created elements to bin */
3781         LOGD("adding created elements to bin");
3782         if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3783                 LOGE("failed to add elements");
3784                 g_list_free(element_bucket);
3785                 goto ERROR;
3786         }
3787
3788         /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3789         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3790         GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3791
3792         /* linking elements in the bucket by added order. */
3793         LOGD("Linking elements in the bucket by added order.");
3794         if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3795                 LOGE("failed to link elements");
3796                 g_list_free(element_bucket);
3797                 goto ERROR;
3798         }
3799
3800         /* done. free allocated variables */
3801         g_list_free(element_bucket);
3802
3803         if (textbin[MMPLAYER_T_QUEUE].gst) {
3804                 GstPad *pad = NULL;
3805                 GstPad *ghostpad = NULL;
3806
3807                 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3808                 if (!pad) {
3809                         LOGE("failed to get sink pad of text queue");
3810                         goto ERROR;
3811                 }
3812
3813                 ghostpad = gst_ghost_pad_new("text_sink", pad);
3814                 gst_object_unref(pad);
3815
3816                 if (!ghostpad) {
3817                         LOGE("failed to create ghostpad of textbin");
3818                         goto ERROR;
3819                 }
3820
3821                 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3822                         LOGE("failed to add ghostpad to textbin");
3823                         gst_object_unref(ghostpad);
3824                         goto ERROR;
3825                 }
3826         }
3827
3828         return MM_ERROR_NONE;
3829
3830 ERROR:
3831
3832         if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3833                 LOGE("remove textbin sink from sink list");
3834                 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3835         }
3836
3837         /* release element at __mmplayer_gst_create_text_sink_bin */
3838         return MM_ERROR_PLAYER_INTERNAL;
3839 }
3840
3841 static int
3842 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3843 {
3844         mmplayer_gst_element_t *textbin = NULL;
3845         GList *element_bucket = NULL;
3846         int surface_type = 0;
3847         gint i = 0;
3848
3849         MMPLAYER_FENTER();
3850
3851         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3852
3853         /* alloc handles */
3854         textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3855         if (!textbin) {
3856                 LOGE("failed to allocate memory for textbin");
3857                 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3858         }
3859
3860         /* create bin */
3861         textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3862         textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3863         if (!textbin[MMPLAYER_T_BIN].gst) {
3864                 LOGE("failed to create textbin");
3865                 goto ERROR;
3866         }
3867
3868         /* take it */
3869         player->pipeline->textbin = textbin;
3870
3871         /* fakesink */
3872         mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3873         LOGD("surface type for subtitle : %d", surface_type);
3874         switch (surface_type) {
3875         case MM_DISPLAY_SURFACE_OVERLAY:
3876         case MM_DISPLAY_SURFACE_NULL:
3877         case MM_DISPLAY_SURFACE_REMOTE:
3878                 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3879                         LOGE("failed to make plain text elements");
3880                         goto ERROR;
3881                 }
3882                 break;
3883         default:
3884                 goto ERROR;
3885                 break;
3886         }
3887
3888         MMPLAYER_FLEAVE();
3889
3890         return MM_ERROR_NONE;
3891
3892 ERROR:
3893
3894         LOGD("ERROR : releasing textbin");
3895
3896         g_list_free(element_bucket);
3897
3898         /* release signal */
3899         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3900
3901         /* release element which are not added to bin */
3902         for (i = 1; i < MMPLAYER_T_NUM; i++) {
3903                 /* NOTE : skip bin */
3904                 if (textbin[i].gst) {
3905                         GstObject *parent = NULL;
3906                         parent = gst_element_get_parent(textbin[i].gst);
3907
3908                         if (!parent) {
3909                                 gst_object_unref(GST_OBJECT(textbin[i].gst));
3910                                 textbin[i].gst = NULL;
3911                         } else {
3912                                 gst_object_unref(GST_OBJECT(parent));
3913                         }
3914                 }
3915         }
3916
3917         /* release textbin with it's children */
3918         if (textbin[MMPLAYER_T_BIN].gst)
3919                 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3920
3921         MMPLAYER_FREEIF(textbin);
3922         player->pipeline->textbin = NULL;
3923
3924         MMPLAYER_FLEAVE();
3925         return MM_ERROR_PLAYER_INTERNAL;
3926 }
3927
3928 static int
3929 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3930 {
3931         mmplayer_gst_element_t *mainbin = NULL;
3932         mmplayer_gst_element_t *textbin = NULL;
3933         MMHandleType attrs = 0;
3934         GstElement *subsrc = NULL;
3935         GstElement *subparse = NULL;
3936         gchar *subtitle_uri = NULL;
3937         const gchar *charset = NULL;
3938         GstPad *pad = NULL;
3939
3940         MMPLAYER_FENTER();
3941
3942         /* get mainbin */
3943         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3944                                                                 player->pipeline &&
3945                                                                 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3946
3947         mainbin = player->pipeline->mainbin;
3948
3949         attrs = MMPLAYER_GET_ATTRS(player);
3950         if (!attrs) {
3951                 LOGE("cannot get content attribute");
3952                 return MM_ERROR_PLAYER_INTERNAL;
3953         }
3954
3955         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3956         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3957                 LOGE("subtitle uri is not proper filepath.");
3958                 return MM_ERROR_PLAYER_INVALID_URI;
3959         }
3960
3961         if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3962                 LOGE("failed to get storage info of subtitle path");
3963                 return MM_ERROR_PLAYER_INVALID_URI;
3964         }
3965
3966         SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3967
3968         MMPLAYER_SUBTITLE_INFO_LOCK(player);
3969         player->subtitle_language_list = NULL;
3970         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3971
3972         /* create the subtitle source */
3973         subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3974         if (!subsrc) {
3975                 LOGE("failed to create filesrc element");
3976                 goto ERROR;
3977         }
3978         g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3979
3980         mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3981         mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3982
3983         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3984                 LOGW("failed to add queue");
3985                 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3986                 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3987                 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3988                 goto ERROR;
3989         }
3990
3991         /* subparse */
3992         subparse = gst_element_factory_make("subparse", "subtitle_parser");
3993         if (!subparse) {
3994                 LOGE("failed to create subparse element");
3995                 goto ERROR;
3996         }
3997
3998         charset = _mmplayer_get_charset(subtitle_uri);
3999         if (charset) {
4000                 LOGD("detected charset is %s", charset);
4001                 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4002         }
4003
4004         mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4005         mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4006
4007         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4008                 LOGW("failed to add subparse");
4009                 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4010                 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4011                 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4012                 goto ERROR;
4013         }
4014
4015         if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4016                 LOGW("failed to link subsrc and subparse");
4017                 goto ERROR;
4018         }
4019
4020         player->play_subtitle = TRUE;
4021         player->adjust_subtitle_pos = 0;
4022
4023         LOGD("play subtitle using subtitle file");
4024
4025         if (player->pipeline->textbin == NULL) {
4026                 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4027                         LOGE("failed to create text sink bin. continuing without text");
4028                         goto ERROR;
4029                 }
4030
4031                 textbin = player->pipeline->textbin;
4032
4033                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4034                         LOGW("failed to add textbin");
4035
4036                         /* release signal */
4037                         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4038
4039                         /* release textbin with it's children */
4040                         gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4041                         MMPLAYER_FREEIF(player->pipeline->textbin);
4042                         player->pipeline->textbin = textbin = NULL;
4043                         goto ERROR;
4044                 }
4045
4046                 LOGD("link text input selector and textbin ghost pad");
4047
4048                 player->textsink_linked = 1;
4049                 player->external_text_idx = 0;
4050                 LOGI("textsink is linked");
4051         } else {
4052                 textbin = player->pipeline->textbin;
4053                 LOGD("text bin has been created. reuse it.");
4054                 player->external_text_idx = 1;
4055         }
4056
4057         if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4058                 LOGW("failed to link subparse and textbin");
4059                 goto ERROR;
4060         }
4061
4062         pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4063         if (!pad) {
4064                 LOGE("failed to get sink pad from textsink to probe data");
4065                 goto ERROR;
4066         }
4067
4068         gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4069                                 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4070
4071         gst_object_unref(pad);
4072         pad = NULL;
4073
4074         /* create dot. for debugging */
4075         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4076         MMPLAYER_FLEAVE();
4077
4078         return MM_ERROR_NONE;
4079
4080 ERROR:
4081         /* release text pipeline resource */
4082         player->textsink_linked = 0;
4083
4084         /* release signal */
4085         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4086
4087         if (player->pipeline->textbin) {
4088                 LOGE("remove textbin");
4089
4090                 /* release textbin with it's children */
4091                 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4092                 MMPLAYER_FREEIF(player->pipeline->textbin);
4093                 player->pipeline->textbin = NULL;
4094
4095         }
4096
4097         /* release subtitle elem */
4098         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4099         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4100
4101         return MM_ERROR_PLAYER_INTERNAL;
4102 }
4103
4104 gboolean
4105 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4106 {
4107         mmplayer_t *player = (mmplayer_t *)data;
4108         MMMessageParamType msg = {0, };
4109         GstClockTime duration = 0;
4110         gpointer text = NULL;
4111         guint text_size = 0;
4112         gboolean ret = TRUE;
4113         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4114
4115         MMPLAYER_FENTER();
4116
4117         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4118         MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4119
4120         if (player->is_subtitle_force_drop) {
4121                 LOGW("subtitle is dropped forcedly.");
4122                 return ret;
4123         }
4124
4125         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4126         text = mapinfo.data;
4127         text_size = mapinfo.size;
4128
4129         if (player->set_mode.subtitle_off) {
4130                 LOGD("subtitle is OFF.");
4131                 return TRUE;
4132         }
4133
4134         if (!text || (text_size == 0)) {
4135                 LOGD("There is no subtitle to be displayed.");
4136                 return TRUE;
4137         }
4138
4139         msg.data = (void *)text;
4140
4141         duration = GST_BUFFER_DURATION(buffer);
4142
4143         if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4144                 if (player->duration > GST_BUFFER_PTS(buffer))
4145                         duration = player->duration - GST_BUFFER_PTS(buffer);
4146                 else
4147                         duration = 0;
4148                 LOGI("subtitle duration is invalid, subtitle duration change "
4149                         "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4150         }
4151         msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4152
4153         LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4154
4155         MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4156         gst_buffer_unmap(buffer, &mapinfo);
4157
4158         MMPLAYER_FLEAVE();
4159
4160         return ret;
4161 }
4162
4163 static GstPadProbeReturn
4164 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4165 {
4166         mmplayer_t *player = (mmplayer_t *)u_data;
4167         GstClockTime cur_timestamp = 0;
4168         gint64 adjusted_timestamp = 0;
4169         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4170
4171         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4172
4173         if (player->set_mode.subtitle_off) {
4174                 LOGD("subtitle is OFF.");
4175                 return TRUE;
4176         }
4177
4178         if (player->adjust_subtitle_pos == 0) {
4179                 LOGD("nothing to do");
4180                 return TRUE;
4181         }
4182
4183         cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4184         adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4185
4186         if (adjusted_timestamp < 0) {
4187                 LOGD("adjusted_timestamp under zero");
4188                 MMPLAYER_FLEAVE();
4189                 return FALSE;
4190         }
4191
4192         GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4193         LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4194                                 GST_TIME_ARGS(cur_timestamp),
4195                                 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4196
4197         return GST_PAD_PROBE_OK;
4198 }
4199
4200 static int
4201 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4202 {
4203         MMPLAYER_FENTER();
4204
4205         /* check player and subtitlebin are created */
4206         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4207         MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4208
4209         if (position == 0) {
4210                 LOGD("nothing to do");
4211                 MMPLAYER_FLEAVE();
4212                 return MM_ERROR_NONE;
4213         }
4214
4215         /* check current position */
4216         player->adjust_subtitle_pos = position;
4217
4218         LOGD("save adjust_subtitle_pos in player");
4219
4220         MMPLAYER_FLEAVE();
4221
4222         return MM_ERROR_NONE;
4223 }
4224
4225 /**
4226  * This function is to create  audio or video pipeline for playing.
4227  *
4228  * @param       player          [in]    handle of player
4229  *
4230  * @return      This function returns zero on success.
4231  * @remark
4232  * @see
4233  */
4234 static int
4235 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4236 {
4237         int ret = MM_ERROR_NONE;
4238         mmplayer_gst_element_t *mainbin = NULL;
4239         MMHandleType attrs = 0;
4240
4241         MMPLAYER_FENTER();
4242         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4243
4244         /* get profile attribute */
4245         attrs = MMPLAYER_GET_ATTRS(player);
4246         if (!attrs) {
4247                 LOGE("failed to get content attribute");
4248                 goto INIT_ERROR;
4249         }
4250
4251         /* create pipeline handles */
4252         if (player->pipeline) {
4253                 LOGE("pipeline should be released before create new one");
4254                 goto INIT_ERROR;
4255         }
4256
4257         player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4258
4259         /* create mainbin */
4260         mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4261         if (mainbin == NULL)
4262                 goto INIT_ERROR;
4263
4264         /* create pipeline */
4265         mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4266         mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4267         if (!mainbin[MMPLAYER_M_PIPE].gst) {
4268                 LOGE("failed to create pipeline");
4269                 g_free(mainbin);
4270                 goto INIT_ERROR;
4271         }
4272
4273         player->pipeline->mainbin = mainbin;
4274
4275         /* create the source and decoder elements */
4276         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4277                 ret = _mmplayer_gst_build_es_pipeline(player);
4278         } else {
4279                 if (MMPLAYER_USE_DECODEBIN(player))
4280                         ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4281                 else
4282                         ret = _mmplayer_gst_build_pipeline_with_src(player);
4283         }
4284
4285         if (ret != MM_ERROR_NONE) {
4286                 LOGE("failed to create some elements");
4287                 goto INIT_ERROR;
4288         }
4289
4290         /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4291         if (__mmplayer_check_subtitle(player)
4292                 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4293                 LOGE("failed to create text pipeline");
4294
4295         /* add bus watch */
4296         ret = _mmplayer_gst_add_bus_watch(player);
4297         if (ret != MM_ERROR_NONE) {
4298                 LOGE("failed to add bus watch");
4299                 goto INIT_ERROR;
4300         }
4301
4302         MMPLAYER_FLEAVE();
4303         return MM_ERROR_NONE;
4304
4305 INIT_ERROR:
4306         _mmplayer_bus_watcher_remove(player);
4307         __mmplayer_gst_destroy_pipeline(player);
4308         return MM_ERROR_PLAYER_INTERNAL;
4309 }
4310
4311 static void
4312 __mmplayer_reset_gapless_state(mmplayer_t *player)
4313 {
4314         MMPLAYER_FENTER();
4315         MMPLAYER_RETURN_IF_FAIL(player
4316                 && player->pipeline
4317                 && player->pipeline->audiobin
4318                 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4319
4320         memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4321
4322         MMPLAYER_FLEAVE();
4323         return;
4324 }
4325
4326 static int
4327 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4328 {
4329         gint timeout = 0;
4330         int ret = MM_ERROR_NONE;
4331
4332         MMPLAYER_FENTER();
4333
4334         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4335
4336         /* cleanup stuffs */
4337         MMPLAYER_FREEIF(player->type);
4338         player->no_more_pad = FALSE;
4339         player->num_dynamic_pad = 0;
4340
4341         MMPLAYER_SUBTITLE_INFO_LOCK(player);
4342         player->subtitle_language_list = NULL;
4343         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4344
4345         MMPLAYER_RECONFIGURE_LOCK(player);
4346         __mmplayer_reset_gapless_state(player);
4347         MMPLAYER_RECONFIGURE_UNLOCK(player);
4348
4349         if (player->streamer) {
4350                 _mm_player_streaming_initialize(player->streamer, FALSE);
4351                 _mm_player_streaming_destroy(player->streamer);
4352                 player->streamer = NULL;
4353         }
4354
4355         /* cleanup unlinked mime type */
4356         MMPLAYER_FREEIF(player->unlinked_audio_mime);
4357         MMPLAYER_FREEIF(player->unlinked_video_mime);
4358         MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4359
4360         /* cleanup running stuffs */
4361         _mmplayer_cancel_eos_timer(player);
4362
4363         /* cleanup gst stuffs */
4364         if (player->pipeline) {
4365                 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4366                 GstTagList *tag_list = player->pipeline->tag_list;
4367
4368                 /* first we need to disconnect all signal hander */
4369                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4370
4371                 if (mainbin) {
4372                         mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4373                         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4374                         mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4375                         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4376                         gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4377                         gst_object_unref(bus);
4378
4379                         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4380                         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4381                         if (ret != MM_ERROR_NONE) {
4382                                 LOGE("fail to change state to NULL");
4383                                 return MM_ERROR_PLAYER_INTERNAL;
4384                         }
4385
4386                         LOGW("succeeded in changing state to NULL");
4387
4388                         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4389
4390                         /* free fakesink */
4391                         if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4392                                 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4393
4394                         MMPLAYER_FREEIF(audiobin);
4395                         MMPLAYER_FREEIF(videobin);
4396                         MMPLAYER_FREEIF(textbin);
4397                         MMPLAYER_FREEIF(mainbin);
4398                 }
4399
4400                 if (tag_list)
4401                         gst_tag_list_unref(tag_list);
4402
4403                 MMPLAYER_FREEIF(player->pipeline);
4404         }
4405         MMPLAYER_FREEIF(player->album_art);
4406
4407         if (player->type_caps) {
4408                 gst_caps_unref(player->type_caps);
4409                 player->type_caps = NULL;
4410         }
4411
4412         if (player->v_stream_caps) {
4413                 gst_caps_unref(player->v_stream_caps);
4414                 player->v_stream_caps = NULL;
4415         }
4416
4417         if (player->a_stream_caps) {
4418                 gst_caps_unref(player->a_stream_caps);
4419                 player->a_stream_caps = NULL;
4420         }
4421
4422         if (player->s_stream_caps) {
4423                 gst_caps_unref(player->s_stream_caps);
4424                 player->s_stream_caps = NULL;
4425         }
4426         _mmplayer_track_destroy(player);
4427
4428         if (player->sink_elements)
4429                 g_list_free(player->sink_elements);
4430         player->sink_elements = NULL;
4431
4432         if (player->bufmgr) {
4433                 tbm_bufmgr_deinit(player->bufmgr);
4434                 player->bufmgr = NULL;
4435         }
4436
4437         LOGW("finished destroy pipeline");
4438
4439         MMPLAYER_FLEAVE();
4440
4441         return ret;
4442 }
4443
4444 static int
4445 __mmplayer_gst_realize(mmplayer_t *player)
4446 {
4447         gint timeout = 0;
4448         int ret = MM_ERROR_NONE;
4449
4450         MMPLAYER_FENTER();
4451
4452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4453
4454         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4455
4456         ret = __mmplayer_gst_create_pipeline(player);
4457         if (ret) {
4458                 LOGE("failed to create pipeline");
4459                 return ret;
4460         }
4461
4462         /* set pipeline state to READY */
4463         /* NOTE : state change to READY must be performed sync. */
4464         timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4465         ret = _mmplayer_gst_set_state(player,
4466                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4467
4468         if (ret != MM_ERROR_NONE) {
4469                 /* return error if failed to set state */
4470                 LOGE("failed to set READY state");
4471                 return ret;
4472         }
4473
4474         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4475
4476         /* create dot before error-return. for debugging */
4477         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4478
4479         MMPLAYER_FLEAVE();
4480
4481         return ret;
4482 }
4483
4484 static int
4485 __mmplayer_gst_unrealize(mmplayer_t *player)
4486 {
4487         int ret = MM_ERROR_NONE;
4488
4489         MMPLAYER_FENTER();
4490
4491         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4492
4493         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4494         MMPLAYER_PRINT_STATE(player);
4495
4496         /* release miscellaneous information */
4497         __mmplayer_release_misc(player);
4498
4499         /* destroy pipeline */
4500         ret = __mmplayer_gst_destroy_pipeline(player);
4501         if (ret != MM_ERROR_NONE) {
4502                 LOGE("failed to destroy pipeline");
4503                 return ret;
4504         }
4505
4506         /* release miscellaneous information.
4507            these info needs to be released after pipeline is destroyed. */
4508         __mmplayer_release_misc_post(player);
4509
4510         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4511
4512         MMPLAYER_FLEAVE();
4513
4514         return ret;
4515 }
4516
4517 static int
4518 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4519 {
4520         MMPLAYER_FENTER();
4521
4522         if (!player) {
4523                 LOGW("set_message_callback is called with invalid player handle");
4524                 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4525         }
4526
4527         player->msg_cb = callback;
4528         player->msg_cb_param = user_param;
4529
4530         LOGD("msg_cb : %p     msg_cb_param : %p", callback, user_param);
4531
4532         MMPLAYER_FLEAVE();
4533
4534         return MM_ERROR_NONE;
4535 }
4536
4537 int
4538 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4539 {
4540         int ret = MM_ERROR_NONE;
4541         char *path = NULL;
4542
4543         MMPLAYER_FENTER();
4544
4545         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4546         MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4547         MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4548
4549         memset(data, 0, sizeof(mmplayer_parse_profile_t));
4550
4551         if (strstr(uri, "es_buff://")) {
4552                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4553         } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4554                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4555         } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4556                 gchar *tmp = NULL;
4557                 tmp = g_ascii_strdown(uri, strlen(uri));
4558                 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4559                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4560                 else
4561                         __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4562                 g_free(tmp);
4563         } else if (strstr(uri, "mms://")) {
4564                 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4565         } else if ((path = strstr(uri, "mem://"))) {
4566                 ret = __mmplayer_set_mem_uri(data, path, param);
4567         } else {
4568                 ret = __mmplayer_set_file_uri(data, uri);
4569         }
4570
4571         if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4572                 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4573         else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4574                 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4575
4576         /* dump parse result */
4577         SECURE_LOGW("incoming uri : %s", uri);
4578         LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4579                 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4580
4581         MMPLAYER_FLEAVE();
4582
4583         return ret;
4584 }
4585
4586 static int
4587 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4588                 void *user_data)
4589 {
4590         mmplayer_t *player = NULL;
4591         MMMessageParamType msg = {0, };
4592         gint64 pos = 0;
4593         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4594
4595         MMPLAYER_FENTER();
4596
4597         if (!user_data) {
4598                 LOGE("user_data is null");
4599                 return TRUE;
4600         }
4601
4602         player = (mmplayer_t *)user_data;
4603
4604         if (!player->pipeline || !player->attrs) {
4605                 LOGW("not initialized");
4606                 return TRUE;
4607         }
4608
4609         LOGD("cmd lock player, cmd state : %d", player->cmd);
4610         MMPLAYER_CMD_LOCK(player);
4611         LOGD("cmd locked player");
4612
4613         if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4614                 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4615                 LOGW("player already destroyed");
4616                 MMPLAYER_CMD_UNLOCK(player);
4617                 return TRUE;
4618         }
4619
4620         player->interrupted_by_resource = TRUE;
4621
4622         MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4623
4624         /* get last play position */
4625         if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4626                 msg.union_type = MM_MSG_UNION_TIME;
4627                 msg.time.elapsed = pos;
4628                 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4629         } else {
4630                 LOGW("failed to get play position.");
4631         }
4632
4633         LOGD("video resource conflict so, resource will be freed by unrealizing");
4634         if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4635                 LOGE("failed to unrealize");
4636
4637         MMPLAYER_CMD_UNLOCK(player);
4638
4639         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4640                 player->hw_resource[res_idx] = NULL;
4641         }
4642
4643         MMPLAYER_FLEAVE();
4644         return TRUE; /* release all the resources */
4645 }
4646
4647 static void
4648 __mmplayer_initialize_video_roi(mmplayer_t *player)
4649 {
4650         player->video_roi.scale_x = 0.0;
4651         player->video_roi.scale_y = 0.0;
4652         player->video_roi.scale_width = 1.0;
4653         player->video_roi.scale_height = 1.0;
4654 }
4655
4656 int
4657 _mmplayer_create_player(MMHandleType handle)
4658 {
4659         int ret = MM_ERROR_PLAYER_INTERNAL;
4660         bool enabled = false;
4661
4662         mmplayer_t *player = MM_PLAYER_CAST(handle);
4663
4664         MMPLAYER_FENTER();
4665
4666         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4667
4668         /* initialize player state */
4669         MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4670         MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4671         MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4672         MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4673
4674         /* check current state */
4675         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4676
4677         /* construct attributes */
4678         player->attrs = _mmplayer_construct_attribute(handle);
4679
4680         if (!player->attrs) {
4681                 LOGE("Failed to construct attributes");
4682                 return ret;
4683         }
4684
4685         /* initialize gstreamer with configured parameter */
4686         if (!__mmplayer_init_gstreamer(player)) {
4687                 LOGE("Initializing gstreamer failed");
4688                 _mmplayer_deconstruct_attribute(handle);
4689                 return ret;
4690         }
4691
4692         /* create lock. note that g_tread_init() has already called in gst_init() */
4693         g_mutex_init(&player->fsink_lock);
4694
4695         /* create update tag lock */
4696         g_mutex_init(&player->update_tag_lock);
4697
4698         /* create gapless play mutex */
4699         g_mutex_init(&player->gapless_play_thread_mutex);
4700
4701         /* create gapless play cond */
4702         g_cond_init(&player->gapless_play_thread_cond);
4703
4704         /* create gapless play thread */
4705         player->gapless_play_thread =
4706                 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4707         if (!player->gapless_play_thread) {
4708                 LOGE("failed to create gapless play thread");
4709                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4710                 g_mutex_clear(&player->gapless_play_thread_mutex);
4711                 g_cond_clear(&player->gapless_play_thread_cond);
4712                 goto ERROR;
4713         }
4714
4715         player->bus_msg_q = g_queue_new();
4716         if (!player->bus_msg_q) {
4717                 LOGE("failed to create queue for bus_msg");
4718                 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4719                 goto ERROR;
4720         }
4721
4722         ret = _mmplayer_initialize_video_capture(player);
4723         if (ret != MM_ERROR_NONE) {
4724                 LOGW("video capture is not supported");
4725                 /* do not handle as error for headless profile */
4726         }
4727
4728         /* initialize resource manager */
4729         if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4730                 __resource_release_cb, player, &player->resource_manager)
4731                 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4732                 LOGE("failed to create resource manager");
4733                 ret = MM_ERROR_PLAYER_INTERNAL;
4734                 goto ERROR;
4735         }
4736
4737         /* create video bo lock and cond */
4738         g_mutex_init(&player->video_bo_mutex);
4739         g_cond_init(&player->video_bo_cond);
4740
4741         /* create subtitle info lock and cond */
4742         g_mutex_init(&player->subtitle_info_mutex);
4743         g_cond_init(&player->subtitle_info_cond);
4744
4745         player->streaming_type = STREAMING_SERVICE_NONE;
4746
4747         /* give default value of audio effect setting */
4748         player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4749         player->sound.rg_enable = false;
4750         player->playback_rate = DEFAULT_PLAYBACK_RATE;
4751
4752         player->play_subtitle = FALSE;
4753         player->has_closed_caption = FALSE;
4754         player->pending_resume = FALSE;
4755         if (player->ini.dump_element_keyword[0][0] == '\0')
4756                 player->ini.set_dump_element_flag = FALSE;
4757         else
4758                 player->ini.set_dump_element_flag = TRUE;
4759
4760         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4761         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4762         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4763
4764         /* Set video360 settings to their defaults for just-created player.
4765          * */
4766
4767         player->is_360_feature_enabled = FALSE;
4768         if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4769                 LOGI("spherical feature info: %d", enabled);
4770                 if (enabled)
4771                         player->is_360_feature_enabled = TRUE;
4772         } else {
4773                 LOGE("failed to get spherical feature info");
4774         }
4775
4776         player->is_content_spherical = FALSE;
4777         player->is_video360_enabled = TRUE;
4778         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4779         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4780         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4781         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4782         player->video360_zoom = 1.0f;
4783         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4784         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4785
4786         __mmplayer_initialize_video_roi(player);
4787
4788         /* set player state to null */
4789         MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4790         MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4791
4792         MMPLAYER_FLEAVE();
4793
4794         return MM_ERROR_NONE;
4795
4796 ERROR:
4797         /* free lock */
4798         g_mutex_clear(&player->fsink_lock);
4799         /* free update tag lock */
4800         g_mutex_clear(&player->update_tag_lock);
4801         g_queue_free(player->bus_msg_q);
4802         player->bus_msg_q = NULL;
4803         /* free gapless play thread */
4804         if (player->gapless_play_thread) {
4805                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4806                 player->gapless_play_thread_exit = TRUE;
4807                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4808                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4809
4810                 g_thread_join(player->gapless_play_thread);
4811                 player->gapless_play_thread = NULL;
4812
4813                 g_mutex_clear(&player->gapless_play_thread_mutex);
4814                 g_cond_clear(&player->gapless_play_thread_cond);
4815         }
4816
4817         /* release attributes */
4818         _mmplayer_deconstruct_attribute(handle);
4819
4820         MMPLAYER_FLEAVE();
4821
4822         return ret;
4823 }
4824
4825 static gboolean
4826 __mmplayer_init_gstreamer(mmplayer_t *player)
4827 {
4828         static gboolean initialized = FALSE;
4829         static const int max_argc = 50;
4830         gint *argc = NULL;
4831         gchar **argv = NULL;
4832         gchar **argv2 = NULL;
4833         GError *err = NULL;
4834         int i = 0;
4835         int arg_count = 0;
4836
4837         if (initialized) {
4838                 LOGD("gstreamer already initialized.");
4839                 return TRUE;
4840         }
4841
4842         /* alloc */
4843         argc = malloc(sizeof(int));
4844         argv = malloc(sizeof(gchar *) * max_argc);
4845         argv2 = malloc(sizeof(gchar *) * max_argc);
4846
4847         if (!argc || !argv || !argv2)
4848                 goto ERROR;
4849
4850         memset(argv, 0, sizeof(gchar *) * max_argc);
4851         memset(argv2, 0, sizeof(gchar *) * max_argc);
4852
4853         /* add initial */
4854         *argc = 1;
4855         argv[0] = g_strdup("mmplayer");
4856
4857         /* add gst_param */
4858         for (i = 0; i < 5; i++) {
4859                 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4860                 if (strlen(player->ini.gst_param[i]) > 0) {
4861                         argv[*argc] = g_strdup(player->ini.gst_param[i]);
4862                         (*argc)++;
4863                 }
4864         }
4865
4866         /* we would not do fork for scanning plugins */
4867         argv[*argc] = g_strdup("--gst-disable-registry-fork");
4868         (*argc)++;
4869
4870         /* check disable registry scan */
4871         if (player->ini.skip_rescan) {
4872                 argv[*argc] = g_strdup("--gst-disable-registry-update");
4873                 (*argc)++;
4874         }
4875
4876         /* check disable segtrap */
4877         if (player->ini.disable_segtrap) {
4878                 argv[*argc] = g_strdup("--gst-disable-segtrap");
4879                 (*argc)++;
4880         }
4881
4882         LOGD("initializing gstreamer with following parameter");
4883         LOGD("argc : %d", *argc);
4884         arg_count = *argc;
4885
4886         for (i = 0; i < arg_count; i++) {
4887                 argv2[i] = argv[i];
4888                 LOGD("argv[%d] : %s", i, argv2[i]);
4889         }
4890
4891         /* initializing gstreamer */
4892         if (!gst_init_check(argc, &argv, &err)) {
4893                 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4894                 if (err)
4895                         g_error_free(err);
4896
4897                 goto ERROR;
4898         }
4899         /* release */
4900         for (i = 0; i < arg_count; i++) {
4901 #ifdef __DEBUG__
4902                 LOGD("release - argv[%d] : %s", i, argv2[i]);
4903 #endif
4904                 MMPLAYER_FREEIF(argv2[i]);
4905         }
4906
4907         MMPLAYER_FREEIF(argv);
4908         MMPLAYER_FREEIF(argv2);
4909         MMPLAYER_FREEIF(argc);
4910
4911         /* done */
4912         initialized = TRUE;
4913
4914         return TRUE;
4915
4916 ERROR:
4917
4918         /* release */
4919         for (i = 0; i < arg_count; i++) {
4920                 LOGD("free[%d] : %s", i, argv2[i]);
4921                 MMPLAYER_FREEIF(argv2[i]);
4922         }
4923
4924         MMPLAYER_FREEIF(argv);
4925         MMPLAYER_FREEIF(argv2);
4926         MMPLAYER_FREEIF(argc);
4927
4928         return FALSE;
4929 }
4930
4931 static void
4932 __mmplayer_check_async_state_transition(mmplayer_t *player)
4933 {
4934         GstState element_state = GST_STATE_VOID_PENDING;
4935         GstState element_pending_state = GST_STATE_VOID_PENDING;
4936         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4937         GstElement *element = NULL;
4938         gboolean async = FALSE;
4939
4940         /* check player handle */
4941         MMPLAYER_RETURN_IF_FAIL(player &&
4942                                                 player->pipeline &&
4943                                                 player->pipeline->mainbin &&
4944                                                 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4945
4946         if (player->attrs)
4947                 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4948
4949         if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4950                 LOGD("don't need to check the pipeline state");
4951                 return;
4952         }
4953
4954         MMPLAYER_PRINT_STATE(player);
4955
4956         /* wait for state transition */
4957         element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4958         ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4959
4960         if (ret == GST_STATE_CHANGE_FAILURE) {
4961                 LOGE(" [%s] state : %s   pending : %s",
4962                         GST_ELEMENT_NAME(element),
4963                         gst_element_state_get_name(element_state),
4964                         gst_element_state_get_name(element_pending_state));
4965
4966                 /* dump state of all element */
4967                 _mmplayer_dump_pipeline_state(player);
4968
4969                 return;
4970         }
4971
4972         LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4973         return;
4974 }
4975
4976 int
4977 _mmplayer_destroy(MMHandleType handle)
4978 {
4979         mmplayer_t *player = MM_PLAYER_CAST(handle);
4980
4981         MMPLAYER_FENTER();
4982
4983         /* check player handle */
4984         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4985
4986         /* destroy can called at anytime */
4987         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4988
4989         /* check async state transition */
4990         __mmplayer_check_async_state_transition(player);
4991
4992         /* release gapless play thread */
4993         if (player->gapless_play_thread) {
4994                 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4995                 player->gapless_play_thread_exit = TRUE;
4996                 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4997                 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4998
4999                 LOGD("waiting for gapless play thread exit");
5000                 g_thread_join(player->gapless_play_thread);
5001                 g_mutex_clear(&player->gapless_play_thread_mutex);
5002                 g_cond_clear(&player->gapless_play_thread_cond);
5003                 LOGD("gapless play thread released");
5004         }
5005
5006         _mmplayer_release_video_capture(player);
5007
5008         /* release miscellaneous information */
5009         __mmplayer_release_misc(player);
5010
5011         /* release pipeline */
5012         if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5013                 LOGE("failed to destroy pipeline");
5014                 return MM_ERROR_PLAYER_INTERNAL;
5015         }
5016
5017         __mmplayer_destroy_hw_resource(player);
5018
5019         g_queue_free(player->bus_msg_q);
5020
5021         /* release subtitle info lock and cond */
5022         g_mutex_clear(&player->subtitle_info_mutex);
5023         g_cond_clear(&player->subtitle_info_cond);
5024
5025         __mmplayer_release_dump_list(player->dump_list);
5026
5027         /* release miscellaneous information.
5028            these info needs to be released after pipeline is destroyed. */
5029         __mmplayer_release_misc_post(player);
5030
5031         /* release attributes */
5032         _mmplayer_deconstruct_attribute(handle);
5033
5034         if (player->uri_info.uri_list) {
5035                 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5036                 player->uri_info.uri_list = NULL;
5037         }
5038
5039         /* release lock */
5040         g_mutex_clear(&player->fsink_lock);
5041
5042         /* release lock */
5043         g_mutex_clear(&player->update_tag_lock);
5044
5045         /* release video bo lock and cond */
5046         g_mutex_clear(&player->video_bo_mutex);
5047         g_cond_clear(&player->video_bo_cond);
5048
5049         MMPLAYER_FLEAVE();
5050
5051         return MM_ERROR_NONE;
5052 }
5053
5054 int
5055 _mmplayer_realize(MMHandleType hplayer)
5056 {
5057         mmplayer_t *player = (mmplayer_t *)hplayer;
5058         int ret = MM_ERROR_NONE;
5059         char *uri = NULL;
5060         void *param = NULL;
5061         MMHandleType attrs = 0;
5062
5063         MMPLAYER_FENTER();
5064
5065         /* check player handle */
5066         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5067
5068         /* check current state */
5069         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5070
5071         attrs = MMPLAYER_GET_ATTRS(player);
5072         if (!attrs) {
5073                 LOGE("fail to get attributes.");
5074                 return MM_ERROR_PLAYER_INTERNAL;
5075         }
5076         mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5077         mm_attrs_get_data_by_name(attrs, "profile_user_param", &param);
5078
5079         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5080                 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5081
5082                 if (ret != MM_ERROR_NONE) {
5083                         LOGE("failed to parse profile");
5084                         return ret;
5085                 }
5086         }
5087
5088         if (uri && (strstr(uri, "es_buff://"))) {
5089                 if (strstr(uri, "es_buff://push_mode"))
5090                         player->es_player_push_mode = TRUE;
5091                 else
5092                         player->es_player_push_mode = FALSE;
5093         }
5094
5095         if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5096                 LOGW("mms protocol is not supported format.");
5097                 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5098         }
5099
5100         if (MMPLAYER_IS_STREAMING(player))
5101                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5102         else
5103                 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5104
5105         player->smooth_streaming = FALSE;
5106         player->videodec_linked  = 0;
5107         player->audiodec_linked  = 0;
5108         player->textsink_linked = 0;
5109         player->is_external_subtitle_present = FALSE;
5110         player->is_external_subtitle_added_now = FALSE;
5111         player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5112         player->video360_metadata.is_spherical = -1;
5113         player->is_openal_plugin_used = FALSE;
5114         player->subtitle_language_list = NULL;
5115         player->is_subtitle_force_drop = FALSE;
5116
5117         _mmplayer_track_initialize(player);
5118         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5119
5120         if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5121                 gint prebuffer_ms = 0, rebuffer_ms = 0;
5122
5123                 player->streamer = _mm_player_streaming_create();
5124                 _mm_player_streaming_initialize(player->streamer, TRUE);
5125
5126                 mm_attrs_multiple_get(player->attrs, NULL,
5127                                 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5128                                 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5129
5130                 if (prebuffer_ms > 0) {
5131                         prebuffer_ms = MAX(prebuffer_ms, 1000);
5132                         player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5133                 }
5134
5135                 if (rebuffer_ms > 0) {
5136                         player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5137                         rebuffer_ms = MAX(rebuffer_ms, 1000);
5138                         player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5139                 }
5140
5141                 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5142                                                                 player->streamer->buffering_req.rebuffer_time);
5143         }
5144
5145         /* realize pipeline */
5146         ret = __mmplayer_gst_realize(player);
5147         if (ret != MM_ERROR_NONE)
5148                 LOGE("fail to realize the player.");
5149
5150         MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5151
5152         MMPLAYER_FLEAVE();
5153
5154         return ret;
5155 }
5156
5157 int
5158 _mmplayer_unrealize(MMHandleType hplayer)
5159 {
5160         mmplayer_t *player = (mmplayer_t *)hplayer;
5161         int ret = MM_ERROR_NONE;
5162         int rm_ret = MM_ERROR_NONE;
5163         mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5164
5165         MMPLAYER_FENTER();
5166
5167         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5168
5169         MMPLAYER_CMD_UNLOCK(player);
5170         _mmplayer_bus_watcher_remove(player);
5171         /* destroy the gst bus msg thread which is created during realize.
5172            this funct have to be called before getting cmd lock. */
5173         _mmplayer_bus_msg_thread_destroy(player);
5174         MMPLAYER_CMD_LOCK(player);
5175
5176         /* check current state */
5177         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5178
5179         /* check async state transition */
5180         __mmplayer_check_async_state_transition(player);
5181
5182         /* unrealize pipeline */
5183         ret = __mmplayer_gst_unrealize(player);
5184
5185         for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5186                 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5187                 if (rm_ret != MM_ERROR_NONE)
5188                         LOGE("failed to release [%d] resources", res_idx);
5189         }
5190
5191         player->interrupted_by_resource = FALSE;
5192
5193         MMPLAYER_FLEAVE();
5194         return ret;
5195 }
5196
5197 int
5198 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5199 {
5200         mmplayer_t *player = (mmplayer_t *)hplayer;
5201
5202         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5203
5204         return __mmplayer_gst_set_message_callback(player, callback, user_param);
5205 }
5206
5207 int
5208 _mmplayer_get_state(MMHandleType hplayer, int *state)
5209 {
5210         mmplayer_t *player = (mmplayer_t *)hplayer;
5211
5212         MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5213
5214         *state = MMPLAYER_CURRENT_STATE(player);
5215
5216         return MM_ERROR_NONE;
5217 }
5218
5219 static int
5220 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5221 {
5222         GstElement *vol_element = NULL;
5223         enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5224
5225         MMPLAYER_FENTER();
5226         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5227         MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5228
5229         /* check pipeline handle */
5230         if (!player->pipeline || !player->pipeline->audiobin) {
5231                 LOGD("'%s' will be applied when audiobin is created", prop_name);
5232
5233                 /* NOTE : stored value will be used in create_audiobin
5234                  * returning MM_ERROR_NONE here makes application to able to
5235                  * set audio volume or mute at anytime.
5236                  */
5237                 return MM_ERROR_NONE;
5238         }
5239
5240         if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5241                 volume_elem_id = MMPLAYER_A_SINK;
5242
5243         vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5244         if (!vol_element) {
5245                 LOGE("failed to get vol element %d", volume_elem_id);
5246                 return MM_ERROR_PLAYER_INTERNAL;
5247         }
5248
5249         LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5250
5251         if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5252                 LOGE("there is no '%s' property", prop_name);
5253                 return MM_ERROR_PLAYER_INTERNAL;
5254         }
5255
5256         if (!strcmp(prop_name, "volume")) {
5257                 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5258         } else if (!strcmp(prop_name, "mute")) {
5259                 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5260         } else {
5261                 LOGE("invalid property %s", prop_name);
5262                 return MM_ERROR_PLAYER_INTERNAL;
5263         }
5264
5265         return MM_ERROR_NONE;
5266 }
5267
5268 int
5269 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5270 {
5271         int ret = MM_ERROR_NONE;
5272         mmplayer_t *player = (mmplayer_t *)hplayer;
5273
5274         MMPLAYER_FENTER();
5275         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5276
5277         LOGD("volume = %f", volume);
5278
5279         /* invalid factor range or not */
5280         if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5281                 LOGE("Invalid volume value");
5282                 return MM_ERROR_INVALID_ARGUMENT;
5283         }
5284
5285         player->sound.volume = volume;
5286
5287         ret = __mmplayer_gst_set_volume_property(player, "volume");
5288
5289         MMPLAYER_FLEAVE();
5290         return ret;
5291 }
5292
5293 int
5294 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5295 {
5296         mmplayer_t *player = (mmplayer_t *)hplayer;
5297
5298         MMPLAYER_FENTER();
5299
5300         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5301         MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5302
5303         *volume = player->sound.volume;
5304
5305         LOGD("current vol = %f", *volume);
5306
5307         MMPLAYER_FLEAVE();
5308         return MM_ERROR_NONE;
5309 }
5310
5311 int
5312 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5313 {
5314         int ret = MM_ERROR_NONE;
5315         mmplayer_t *player = (mmplayer_t *)hplayer;
5316
5317         MMPLAYER_FENTER();
5318         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5319
5320         LOGD("mute = %d", mute);
5321
5322         player->sound.mute = mute;
5323
5324         ret = __mmplayer_gst_set_volume_property(player, "mute");
5325
5326         MMPLAYER_FLEAVE();
5327         return ret;
5328 }
5329
5330 int
5331 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5332 {
5333         mmplayer_t *player = (mmplayer_t *)hplayer;
5334
5335         MMPLAYER_FENTER();
5336
5337         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5338         MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5339
5340         *mute = player->sound.mute;
5341
5342         LOGD("current mute = %d", *mute);
5343
5344         MMPLAYER_FLEAVE();
5345
5346         return MM_ERROR_NONE;
5347 }
5348
5349 int
5350 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5351 {
5352         mmplayer_t *player = (mmplayer_t *)hplayer;
5353
5354         MMPLAYER_FENTER();
5355
5356         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5357
5358         player->audio_stream_changed_cb = callback;
5359         player->audio_stream_changed_cb_user_param = user_param;
5360         LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5361
5362         MMPLAYER_FLEAVE();
5363
5364         return MM_ERROR_NONE;
5365 }
5366
5367 int
5368 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5369 {
5370         mmplayer_t *player = (mmplayer_t *)hplayer;
5371
5372         MMPLAYER_FENTER();
5373
5374         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5375
5376         player->audio_decoded_cb = callback;
5377         player->audio_decoded_cb_user_param = user_param;
5378         player->audio_extract_opt = opt;
5379         LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5380
5381         MMPLAYER_FLEAVE();
5382
5383         return MM_ERROR_NONE;
5384 }
5385
5386 int
5387 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5388 {
5389         mmplayer_t *player = (mmplayer_t *)hplayer;
5390
5391         MMPLAYER_FENTER();
5392
5393         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5394
5395         if (callback && !player->bufmgr)
5396                 player->bufmgr = tbm_bufmgr_init(-1);
5397
5398         player->set_mode.video_export = (callback) ? true : false;
5399         player->video_decoded_cb = callback;
5400         player->video_decoded_cb_user_param = user_param;
5401
5402         LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5403
5404         MMPLAYER_FLEAVE();
5405
5406         return MM_ERROR_NONE;
5407 }
5408
5409 int
5410 _mmplayer_start(MMHandleType hplayer)
5411 {
5412         mmplayer_t *player = (mmplayer_t *)hplayer;
5413         gint ret = MM_ERROR_NONE;
5414
5415         MMPLAYER_FENTER();
5416
5417         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5418
5419         /* check current state */
5420         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5421
5422         /* start pipeline */
5423         ret = _mmplayer_gst_start(player);
5424         if (ret != MM_ERROR_NONE)
5425                 LOGE("failed to start player.");
5426
5427         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5428                 LOGD("force playing start even during buffering");
5429                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5430         }
5431
5432         MMPLAYER_FLEAVE();
5433
5434         return ret;
5435 }
5436
5437 /* NOTE: post "not supported codec message" to application
5438  * when one codec is not found during AUTOPLUGGING in MSL.
5439  * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5440  * And, if any codec is not found, don't send message here.
5441  * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5442  */
5443 int
5444 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5445 {
5446         MMMessageParamType msg_param;
5447         memset(&msg_param, 0, sizeof(MMMessageParamType));
5448         gboolean post_msg_direct = FALSE;
5449
5450         MMPLAYER_FENTER();
5451
5452         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5453
5454         LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5455                         player->not_supported_codec, player->can_support_codec);
5456
5457         if (player->not_found_demuxer) {
5458                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5459                 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5460
5461                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5462                 MMPLAYER_FREEIF(msg_param.data);
5463
5464                 return MM_ERROR_NONE;
5465         }
5466
5467         if (player->not_supported_codec) {
5468                 if (player->can_support_codec) {
5469                         // There is one codec to play
5470                         post_msg_direct = TRUE;
5471                 } else {
5472                         if (player->pipeline->audiobin) // Some content has only PCM data in container.
5473                                 post_msg_direct = TRUE;
5474                 }
5475
5476                 if (post_msg_direct) {
5477                         MMMessageParamType msg_param;
5478                         memset(&msg_param, 0, sizeof(MMMessageParamType));
5479
5480                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5481                                 LOGW("not found AUDIO codec, posting error code to application.");
5482
5483                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5484                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5485                         } else if (player->not_supported_codec ==  MISSING_PLUGIN_VIDEO) {
5486                                 LOGW("not found VIDEO codec, posting error code to application.");
5487
5488                                 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5489                                 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5490                         }
5491
5492                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5493
5494                         MMPLAYER_FREEIF(msg_param.data);
5495
5496                         return MM_ERROR_NONE;
5497                 } else {
5498                         // no any supported codec case
5499                         LOGW("not found any codec, posting error code to application.");
5500
5501                         if (player->not_supported_codec ==  MISSING_PLUGIN_AUDIO) {
5502                                 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5503                                 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5504                         } else {
5505                                 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5506                                 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5507                         }
5508
5509                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5510
5511                         MMPLAYER_FREEIF(msg_param.data);
5512                 }
5513         }
5514
5515         MMPLAYER_FLEAVE();
5516
5517         return MM_ERROR_NONE;
5518 }
5519
5520 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5521 {
5522         GstState element_state = GST_STATE_VOID_PENDING;
5523         GstState element_pending_state = GST_STATE_VOID_PENDING;
5524         GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5525         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5526
5527         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5528
5529         MMPLAYER_RECONFIGURE_LOCK(player);
5530         if (!player->gapless.reconfigure) {
5531                 MMPLAYER_RECONFIGURE_UNLOCK(player);
5532                 return;
5533         }
5534
5535         LOGI("reconfigure is under process");
5536         MMPLAYER_RECONFIGURE_WAIT(player);
5537         MMPLAYER_RECONFIGURE_UNLOCK(player);
5538         LOGI("reconfigure is completed.");
5539
5540         result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5541                                 &element_state, &element_pending_state, timeout * GST_SECOND);
5542         if (result == GST_STATE_CHANGE_FAILURE)
5543                 LOGW("failed to get pipeline state in %d sec", timeout);
5544
5545         return;
5546 }
5547
5548 /* NOTE : it should be able to call 'stop' anytime*/
5549 int
5550 _mmplayer_stop(MMHandleType hplayer)
5551 {
5552         mmplayer_t *player = (mmplayer_t *)hplayer;
5553         int ret = MM_ERROR_NONE;
5554
5555         MMPLAYER_FENTER();
5556
5557         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5558
5559         /* check current state */
5560         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5561
5562         /* need to wait till the rebuilding pipeline is completed */
5563         __mmplayer_check_pipeline_reconfigure_state(player);
5564         MMPLAYER_RECONFIGURE_LOCK(player);
5565         __mmplayer_reset_gapless_state(player);
5566         MMPLAYER_RECONFIGURE_UNLOCK(player);
5567
5568         /* NOTE : application should not wait for EOS after calling STOP */
5569         _mmplayer_cancel_eos_timer(player);
5570
5571         /* reset */
5572         player->seek_state = MMPLAYER_SEEK_NONE;
5573
5574         /* stop pipeline */
5575         ret = _mmplayer_gst_stop(player);
5576
5577         if (ret != MM_ERROR_NONE)
5578                 LOGE("failed to stop player.");
5579
5580         MMPLAYER_FLEAVE();
5581
5582         return ret;
5583 }
5584
5585 int
5586 _mmplayer_pause(MMHandleType hplayer)
5587 {
5588         mmplayer_t *player = (mmplayer_t *)hplayer;
5589         gint64 pos_nsec = 0;
5590         gboolean async = FALSE;
5591         gint ret = MM_ERROR_NONE;
5592
5593         MMPLAYER_FENTER();
5594
5595         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5596
5597         /* check current state */
5598         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5599
5600         /* check pipeline reconfigure state */
5601         __mmplayer_check_pipeline_reconfigure_state(player);
5602
5603         switch (MMPLAYER_CURRENT_STATE(player)) {
5604         case MM_PLAYER_STATE_READY:
5605                 {
5606                         /* check prepare async or not.
5607                          * In the case of streaming playback, it's recommended to avoid blocking wait.
5608                          */
5609                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5610                         LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5611
5612                         /* Changing back sync of rtspsrc to async */
5613                         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5614                                 LOGD("async prepare working mode for rtsp");
5615                                 async = TRUE;
5616                         }
5617                 }
5618                 break;
5619
5620         case MM_PLAYER_STATE_PLAYING:
5621                 {
5622                         /* NOTE : store current point to overcome some bad operation
5623                         *(returning zero when getting current position in paused state) of some
5624                         * elements
5625                         */
5626                         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5627                                 LOGW("getting current position failed in paused");
5628
5629                         player->last_position = pos_nsec;
5630
5631                         /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5632                            But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5633                            This causes problem is position calculation during normal pause resume scenarios also.
5634                            Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5635                         if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5636                                 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5637                                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5638                         }
5639                 }
5640                 break;
5641         }
5642
5643         if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5644                 LOGD("doing async pause in case of ms buff src");
5645                 async = TRUE;
5646         }
5647
5648         /* pause pipeline */
5649         ret = _mmplayer_gst_pause(player, async);
5650         if (ret != MM_ERROR_NONE) {
5651                 LOGE("failed to pause player. ret : 0x%x", ret);
5652                 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5653                 return ret;
5654         }
5655
5656         if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5657                 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5658                         LOGE("failed to update display_rotation");
5659         }
5660
5661         MMPLAYER_FLEAVE();
5662         return MM_ERROR_NONE;
5663 }
5664
5665 /* in case of streaming, pause could take long time.*/
5666 int
5667 _mmplayer_abort_pause(MMHandleType hplayer)
5668 {
5669         mmplayer_t *player = (mmplayer_t *)hplayer;
5670         int ret = MM_ERROR_NONE;
5671
5672         MMPLAYER_FENTER();
5673
5674         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5675                                                 player->pipeline &&
5676                                                 player->pipeline->mainbin,
5677                                                 MM_ERROR_PLAYER_NOT_INITIALIZED);
5678
5679         if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5680                 LOGD("set the videobin state to READY");
5681                 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5682                                                         GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5683
5684         }
5685
5686         if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5687                 LOGD("set the audiobin state to READY");
5688                 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5689                                                         GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5690
5691         }
5692
5693         LOGD("set the pipeline state to READY");
5694         ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5695                                                 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5696
5697         if (ret != MM_ERROR_NONE) {
5698                 LOGE("fail to change state to READY");
5699                 return MM_ERROR_PLAYER_INTERNAL;
5700         }
5701
5702         LOGD("succeeded in changing state to READY");
5703         return ret;
5704 }
5705
5706 int
5707 _mmplayer_resume(MMHandleType hplayer)
5708 {
5709         mmplayer_t *player = (mmplayer_t *)hplayer;
5710         int ret = MM_ERROR_NONE;
5711         gboolean async = FALSE;
5712
5713         MMPLAYER_FENTER();
5714
5715         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716
5717         if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5718                 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5719                         player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5720                         return ret;
5721                 }
5722
5723                 /* Changing back sync mode rtspsrc to async */
5724                 LOGD("async resume for rtsp case");
5725                 async = TRUE;
5726         }
5727
5728         /* check current state */
5729         MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5730
5731         ret = _mmplayer_gst_resume(player, async);
5732         if (ret != MM_ERROR_NONE)
5733                 LOGE("failed to resume player.");
5734
5735         if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5736                 LOGD("force resume even during buffering");
5737                 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5738         }
5739
5740         MMPLAYER_FLEAVE();
5741
5742         return ret;
5743 }
5744
5745 int
5746 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5747 {
5748         mmplayer_t *player = (mmplayer_t *)hplayer;
5749         gint64 pos_nsec = 0;
5750         int ret = MM_ERROR_NONE;
5751         bool mute = false;
5752         signed long long start = 0, stop = 0;
5753         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5754         MMPLAYER_FENTER();
5755
5756         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5757         MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5758
5759         /* The sound of video is not supported under 0.0 and over 2.0. */
5760         if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5761                 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5762                         mute = true;
5763         }
5764         _mmplayer_set_mute(hplayer, mute);
5765
5766         if (player->playback_rate == rate)
5767                 return MM_ERROR_NONE;
5768
5769         /* If the position is reached at start potion during fast backward, EOS is posted.
5770          * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5771          */
5772         player->playback_rate = rate;
5773
5774         current_state = MMPLAYER_CURRENT_STATE(player);
5775
5776         if (current_state != MM_PLAYER_STATE_PAUSED)
5777                 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5778
5779         LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5780
5781         if ((current_state == MM_PLAYER_STATE_PAUSED)
5782                 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5783                 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5784                 pos_nsec = player->last_position;
5785         }
5786
5787         if (rate >= 0) {
5788                 start = pos_nsec;
5789                 stop = GST_CLOCK_TIME_NONE;
5790         } else {
5791                 start = GST_CLOCK_TIME_NONE;
5792                 stop = pos_nsec;
5793         }
5794
5795         if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5796                                 player->playback_rate,
5797                                 GST_FORMAT_TIME,
5798                                 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5799                                 GST_SEEK_TYPE_SET, start,
5800                                 GST_SEEK_TYPE_SET, stop)) {
5801                 LOGE("failed to set speed playback");
5802                 return MM_ERROR_PLAYER_SEEK;
5803         }
5804
5805         LOGD("succeeded to set speed playback as %0.1f", rate);
5806
5807         MMPLAYER_FLEAVE();
5808
5809         return MM_ERROR_NONE;;
5810 }
5811
5812 int
5813 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5814 {
5815         mmplayer_t *player = (mmplayer_t *)hplayer;
5816         int ret = MM_ERROR_NONE;
5817
5818         MMPLAYER_FENTER();
5819
5820         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5821
5822         /* check pipeline reconfigure state */
5823         __mmplayer_check_pipeline_reconfigure_state(player);
5824
5825         ret = _mmplayer_gst_set_position(player, position, FALSE);
5826
5827         MMPLAYER_FLEAVE();
5828
5829         return ret;
5830 }
5831
5832 int
5833 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5834 {
5835         mmplayer_t *player = (mmplayer_t *)hplayer;
5836         int ret = MM_ERROR_NONE;
5837
5838         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5839         MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5840
5841         if (g_strrstr(player->type, "video/mpegts"))
5842                 __mmplayer_update_duration_value(player);
5843
5844         *duration = player->duration;
5845         return ret;
5846 }
5847
5848 int
5849 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5850 {
5851         mmplayer_t *player = (mmplayer_t *)hplayer;
5852         int ret = MM_ERROR_NONE;
5853
5854         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5855
5856         ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5857
5858         return ret;
5859 }
5860
5861 int
5862 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5863 {
5864         mmplayer_t *player = (mmplayer_t *)hplayer;
5865         int ret = MM_ERROR_NONE;
5866
5867         MMPLAYER_FENTER();
5868
5869         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5870
5871         ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5872
5873         MMPLAYER_FLEAVE();
5874
5875         return ret;
5876 }
5877
5878 static gboolean
5879 __mmplayer_is_midi_type(gchar *str_caps)
5880 {
5881         if ((g_strrstr(str_caps, "audio/midi")) ||
5882                 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5883                 (g_strrstr(str_caps, "application/x-smaf")) ||
5884                 (g_strrstr(str_caps, "audio/x-imelody")) ||
5885                 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5886                 (g_strrstr(str_caps, "audio/xmf")) ||
5887                 (g_strrstr(str_caps, "audio/mxmf"))) {
5888                 LOGD("midi");
5889                 return TRUE;
5890         }
5891
5892         return FALSE;
5893 }
5894
5895 static gboolean
5896 __mmplayer_is_only_mp3_type(gchar *str_caps)
5897 {
5898         if (g_strrstr(str_caps, "application/x-id3") ||
5899                 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5900                 return TRUE;
5901         return FALSE;
5902 }
5903
5904 void
5905 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5906 {
5907         GstStructure *caps_structure = NULL;
5908         gint samplerate = 0;
5909         gint channels = 0;
5910
5911         MMPLAYER_FENTER();
5912         MMPLAYER_RETURN_IF_FAIL(player && caps);
5913
5914         caps_structure = gst_caps_get_structure(caps, 0);
5915
5916         /* set stream information */
5917         gst_structure_get_int(caps_structure, "rate", &samplerate);
5918         gst_structure_get_int(caps_structure, "channels", &channels);
5919
5920         mm_player_set_attribute((MMHandleType)player, NULL,
5921                         "content_audio_samplerate", samplerate,
5922                         "content_audio_channels", channels, NULL);
5923
5924         LOGD("audio samplerate : %d     channels : %d", samplerate, channels);
5925 }
5926
5927 static void
5928 __mmplayer_update_content_type_info(mmplayer_t *player)
5929 {
5930         MMPLAYER_FENTER();
5931         MMPLAYER_RETURN_IF_FAIL(player && player->type);
5932
5933         if (__mmplayer_is_midi_type(player->type)) {
5934                 player->bypass_audio_effect = TRUE;
5935                 return;
5936         }
5937
5938         if (!player->streamer) {
5939                 LOGD("no need to check streaming type");
5940                 return;
5941         }
5942
5943         if (g_strrstr(player->type, "application/x-hls")) {
5944                 /* If it can't know exact type when it parses uri because of redirection case,
5945                  * it will be fixed by typefinder or when doing autoplugging.
5946                  */
5947                 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5948                 player->streamer->is_adaptive_streaming = TRUE;
5949         } else if (g_strrstr(player->type, "application/dash+xml")) {
5950                 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5951                 player->streamer->is_adaptive_streaming = TRUE;
5952         }
5953
5954         /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5955         if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5956                 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5957
5958                 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5959                         if (player->streamer->is_adaptive_streaming)
5960                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5961                         else
5962                                 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5963                 }
5964         }
5965
5966         LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5967         MMPLAYER_FLEAVE();
5968 }
5969
5970 void
5971 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5972         GstCaps *caps, gpointer data)
5973 {
5974         mmplayer_t *player = (mmplayer_t *)data;
5975
5976         MMPLAYER_FENTER();
5977
5978         MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5979
5980         /* store type string */
5981         if (player->type_caps) {
5982                 gst_caps_unref(player->type_caps);
5983                 player->type_caps = NULL;
5984         }
5985
5986         player->type_caps = gst_caps_copy(caps);
5987         MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5988
5989         MMPLAYER_FREEIF(player->type);
5990         player->type = gst_caps_to_string(caps);
5991         if (player->type)
5992                 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5993                                 player, player->type, probability, gst_caps_get_size(caps));
5994
5995         if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5996                 (g_strrstr(player->type, "audio/x-raw-int"))) {
5997                 LOGE("not support media format");
5998
5999                 if (player->msg_posted == FALSE) {
6000                         MMMessageParamType msg_param;
6001                         memset(&msg_param, 0, sizeof(MMMessageParamType));
6002
6003                         msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6004                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6005
6006                         /* don't post more if one was sent already */
6007                         player->msg_posted = TRUE;
6008                 }
6009                 return;
6010         }
6011
6012         __mmplayer_update_content_type_info(player);
6013
6014         if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6015                 GstPad *pad = NULL;
6016
6017                 pad = gst_element_get_static_pad(tf, "src");
6018                 if (!pad) {
6019                         LOGE("fail to get typefind src pad.");
6020                         return;
6021                 }
6022
6023                 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6024                         gboolean async = FALSE;
6025                         LOGE("failed to autoplug %s", player->type);
6026
6027                         mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6028
6029                         if (async && player->msg_posted == FALSE)
6030                                 __mmplayer_handle_missed_plugin(player);
6031                 }
6032                 gst_object_unref(GST_OBJECT(pad));
6033         }
6034         MMPLAYER_FLEAVE();
6035         return;
6036 }
6037
6038 GstElement *
6039 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6040 {
6041         GstElement *decodebin = NULL;
6042
6043         MMPLAYER_FENTER();
6044
6045         /* create decodebin */
6046         decodebin = gst_element_factory_make("decodebin", NULL);
6047
6048         if (!decodebin) {
6049                 LOGE("fail to create decodebin");
6050                 goto ERROR;
6051         }
6052
6053         /* raw pad handling signal */
6054         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6055                                                 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6056
6057         /* no-more-pad pad handling signal */
6058         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6059                                                 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6060
6061         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6062                                                 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6063
6064         /* This signal is emitted when a pad for which there is no further possible
6065            decoding is added to the decodebin.*/
6066         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6067                                                 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6068
6069         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6070            before looking for any elements that can handle that stream.*/
6071         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6072                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6073
6074         if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6075                 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6076                                                         G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6077
6078         /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6079            before looking for any elements that can handle that stream.*/
6080         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6081                                                 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6082
6083         /* This signal is emitted once decodebin has finished decoding all the data.*/
6084         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6085                                                 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6086
6087         /* This signal is emitted when a element is added to the bin.*/
6088         _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6089                                                 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6090
6091 ERROR:
6092         return decodebin;
6093 }
6094
6095 static GstElement *
6096 __mmplayer_gst_make_queue2(mmplayer_t *player)
6097 {
6098         GstElement *queue2 = NULL;
6099         gint64 dur_bytes = 0L;
6100         mmplayer_gst_element_t *mainbin = NULL;
6101         muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6102
6103         MMPLAYER_FENTER();
6104         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6105
6106         mainbin = player->pipeline->mainbin;
6107
6108         queue2 = gst_element_factory_make("queue2", "queue2");
6109         if (!queue2) {
6110                 LOGE("failed to create buffering queue element");
6111                 return NULL;
6112         }
6113
6114         if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6115                 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6116
6117         LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6118
6119         /* NOTE : in case of ts streaming, player could not get the correct duration info *
6120          *                skip the pull mode(file or ring buffering) setting. */
6121         if (dur_bytes > 0) {
6122                 if (!g_strrstr(player->type, "video/mpegts")) {
6123                         type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6124                         player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6125                 }
6126         } else {
6127                 dur_bytes = 0;
6128         }
6129
6130         _mm_player_streaming_set_queue2(player->streamer,
6131                                                                         queue2,
6132                                                                         FALSE,
6133                                                                         type,
6134                                                                         (guint64)dur_bytes); /* no meaning at the moment */
6135
6136         return queue2;
6137 }
6138
6139 gboolean
6140 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6141 {
6142         mmplayer_gst_element_t *mainbin = NULL;
6143         GstElement *decodebin = NULL;
6144         GstElement *queue2 = NULL;
6145         GstPad *sinkpad = NULL;
6146         GstPad *qsrcpad = NULL;
6147
6148         MMPLAYER_FENTER();
6149         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6150
6151         mainbin = player->pipeline->mainbin;
6152
6153         if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6154
6155                 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6156                         LOGW("need to check: muxed buffer is not null");
6157                 }
6158
6159                 queue2 = __mmplayer_gst_make_queue2(player);
6160                 if (!queue2) {
6161                         LOGE("failed to make queue2");
6162                         goto ERROR;
6163                 }
6164
6165                 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6166                         LOGE("failed to add buffering queue");
6167                         goto ERROR;
6168                 }
6169
6170                 sinkpad = gst_element_get_static_pad(queue2, "sink");
6171                 qsrcpad = gst_element_get_static_pad(queue2, "src");
6172
6173                 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6174                         LOGE("failed to link [%s:%s]-[%s:%s]",
6175                                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6176                         goto ERROR;
6177                 }
6178
6179                 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6180                         LOGE("failed to sync queue2 state with parent");
6181                         goto ERROR;
6182                 }
6183
6184                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6185                 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6186
6187                 srcpad = qsrcpad;
6188
6189                 gst_object_unref(GST_OBJECT(sinkpad));
6190                 sinkpad = NULL;
6191         }
6192
6193         /* create decodebin */
6194         decodebin = _mmplayer_gst_make_decodebin(player);
6195         if (!decodebin) {
6196                 LOGE("failed to make decodebin");
6197                 goto ERROR;
6198         }
6199
6200         if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6201                 LOGE("failed to add decodebin");
6202                 goto ERROR;
6203         }
6204
6205         /* to force caps on the decodebin element and avoid reparsing stuff by
6206         * typefind. It also avoids a deadlock in the way typefind activates pads in
6207         * the state change */
6208         g_object_set(decodebin, "sink-caps", caps, NULL);
6209
6210         sinkpad = gst_element_get_static_pad(decodebin, "sink");
6211
6212         if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6213                 LOGE("failed to link [%s:%s]-[%s:%s]",
6214                                 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6215                 goto ERROR;
6216         }
6217
6218         gst_object_unref(GST_OBJECT(sinkpad));
6219         sinkpad = NULL;
6220         gst_object_unref(GST_OBJECT(qsrcpad));
6221         qsrcpad = NULL;
6222
6223         mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6224         mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6225
6226         /* set decodebin property about buffer in streaming playback. *
6227          * in case of HLS/DASH, it does not need to have big buffer   *
6228          * because it is kind of adaptive streaming.                  */
6229         if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6230                 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6231                 gint high_percent = 0;
6232
6233                 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6234                         init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6235
6236                 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6237
6238                 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6239
6240                 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6241                                                                                         "high-percent", high_percent,
6242                                                                                         "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6243                                                                                         "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6244                                                                                         "max-size-buffers", 0, NULL);  // disable or automatic
6245         }
6246
6247         if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6248                 LOGE("failed to sync decodebin state with parent");
6249                 goto ERROR;
6250         }
6251
6252         MMPLAYER_FLEAVE();
6253
6254         return TRUE;
6255
6256 ERROR:
6257
6258         if (sinkpad)
6259                 gst_object_unref(GST_OBJECT(sinkpad));
6260
6261         if (qsrcpad)
6262                 gst_object_unref(GST_OBJECT(qsrcpad));
6263
6264         if (queue2) {
6265                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6266                  * You need to explicitly set elements to the NULL state before
6267                  * dropping the final reference, to allow them to clean up.
6268                  */
6269                 gst_element_set_state(queue2, GST_STATE_NULL);
6270
6271                 /* And, it still has a parent "player".
6272                  * You need to let the parent manage the object instead of unreffing the object directly.
6273                  */
6274                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6275                 gst_object_unref(queue2);
6276                 queue2 = NULL;
6277         }
6278
6279         if (decodebin) {
6280                 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6281                  * You need to explicitly set elements to the NULL state before
6282                  * dropping the final reference, to allow them to clean up.
6283                  */
6284                 gst_element_set_state(decodebin, GST_STATE_NULL);
6285
6286                 /* And, it still has a parent "player".
6287                  * You need to let the parent manage the object instead of unreffing the object directly.
6288                  */
6289
6290                 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6291                 gst_object_unref(decodebin);
6292                 decodebin = NULL;
6293         }
6294
6295         return FALSE;
6296 }
6297
6298 static int
6299 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6300 {
6301         MMPLAYER_FENTER();
6302
6303         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6304         MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6305
6306         LOGD("class : %s, mime : %s", factory_class, mime);
6307
6308         /* add missing plugin */
6309         /* NOTE : msl should check missing plugin for image mime type.
6310          * Some motion jpeg clips can have playable audio track.
6311          * So, msl have to play audio after displaying popup written video format not supported.
6312          */
6313         if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6314                 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6315                         LOGD("not found demuxer");
6316                         player->not_found_demuxer = TRUE;
6317                         player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6318
6319                         goto DONE;
6320                 }
6321         }
6322
6323         if (!g_strrstr(factory_class, "Demuxer")) {
6324                 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6325                         LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6326                                 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6327
6328                         /* check that clip have multi tracks or not */
6329                         if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6330                                 LOGD("video plugin is already linked");
6331                         } else {
6332                                 LOGW("add VIDEO to missing plugin");
6333                                 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6334                                 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6335                         }
6336                 } else if (g_str_has_prefix(mime, "audio")) {
6337                         if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6338                                 LOGD("audio plugin is already linked");
6339                         } else {
6340                                 LOGW("add AUDIO to missing plugin");
6341                                 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6342                                 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6343                         }
6344                 }
6345         }
6346
6347 DONE:
6348         MMPLAYER_FLEAVE();
6349
6350         return MM_ERROR_NONE;
6351 }
6352
6353 void
6354 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6355 {
6356         mmplayer_t *player = (mmplayer_t *)data;
6357
6358         MMPLAYER_FENTER();
6359
6360         MMPLAYER_RETURN_IF_FAIL(player);
6361
6362         /* remove fakesink. */
6363         if (!_mmplayer_gst_remove_fakesink(player,
6364                                 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6365                 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6366                  * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6367                  * source element are not same. To overcome this situation, this function will called
6368                  * several places and several times. Therefore, this is not an error case.
6369                  */
6370                 return;
6371         }
6372
6373         LOGD("[handle: %p] pipeline has completely constructed", player);
6374
6375         if ((player->msg_posted == FALSE) &&
6376                 (player->cmd >= MMPLAYER_COMMAND_START))
6377                 __mmplayer_handle_missed_plugin(player);
6378
6379         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6380 }
6381
6382 static int
6383 __mmplayer_check_profile(void)
6384 {
6385         char *profileName;
6386         static int profile_tv = -1;
6387
6388         if (__builtin_expect(profile_tv != -1, 1))
6389                 return profile_tv;
6390
6391         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6392         switch (*profileName) {
6393         case 't':
6394         case 'T':
6395                 profile_tv = 1;
6396                 break;
6397         default:
6398                 profile_tv = 0;
6399                 break;
6400         }
6401         free(profileName);
6402
6403         return profile_tv;
6404 }
6405
6406 static gboolean
6407 __mmplayer_get_next_uri(mmplayer_t *player)
6408 {
6409         mmplayer_parse_profile_t profile;
6410         gint uri_idx = 0;
6411         guint num_of_list = 0;
6412         char *uri = NULL;
6413
6414         num_of_list = g_list_length(player->uri_info.uri_list);
6415         uri_idx = player->uri_info.uri_idx;
6416
6417         LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6418         for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6419                 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6420                 if (!uri) {
6421                         LOGW("next uri does not exist");
6422                         continue;
6423                 }
6424
6425                 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6426                         LOGE("failed to parse profile");
6427                         continue;
6428                 }
6429
6430                 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6431                         (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6432                         LOGW("uri type is not supported(%d)", profile.uri_type);
6433                         continue;
6434                 }
6435
6436                 LOGD("success to find next uri %d", uri_idx);
6437                 break;
6438         }
6439
6440         if (!uri || uri_idx == num_of_list) {
6441                 LOGE("failed to find next uri");
6442                 return FALSE;
6443         }
6444
6445         player->uri_info.uri_idx = uri_idx;
6446         if (mm_player_set_attribute((MMHandleType)player, NULL,
6447                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6448                 LOGE("failed to set attribute");
6449                 return FALSE;
6450         }
6451
6452         SECURE_LOGD("next playback uri: %s", uri);
6453         return TRUE;
6454 }
6455
6456 static gboolean
6457 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6458 {
6459 #define REPEAT_COUNT_INFINITE -1
6460 #define REPEAT_COUNT_MIN 2
6461 #define ORIGINAL_URI_ONLY 1
6462
6463         MMHandleType attrs = 0;
6464         gint video = 0;
6465         gint count = 0;
6466         gint gapless = 0;
6467         guint num_of_uri = 0;
6468         int profile_tv = -1;
6469
6470         MMPLAYER_FENTER();
6471
6472         LOGD("checking for gapless play option");
6473
6474         if (player->build_audio_offload) {
6475                 LOGE("offload path is not supportable.");
6476                 goto ERROR;
6477         }
6478
6479         if (player->pipeline->textbin) {
6480                 LOGE("subtitle path is enabled. gapless play is not supported.");
6481                 goto ERROR;
6482         }
6483
6484         attrs = MMPLAYER_GET_ATTRS(player);
6485         if (!attrs) {
6486                 LOGE("fail to get attributes.");
6487                 goto ERROR;
6488         }
6489
6490         mm_attrs_multiple_get(player->attrs, NULL,
6491                         "content_video_found", &video,
6492                         "profile_play_count", &count,
6493                         MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6494
6495         /* gapless playback is not supported in case of video at TV profile. */
6496         profile_tv = __mmplayer_check_profile();
6497         if (profile_tv && video) {
6498                 LOGW("not support video gapless playback");
6499                 goto ERROR;
6500         }
6501
6502         /* check repeat count in case of audio */
6503         if (!gapless &&
6504                 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6505                 LOGW("gapless is disabled");
6506                 goto ERROR;
6507         }
6508
6509         num_of_uri = g_list_length(player->uri_info.uri_list);
6510
6511         LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6512
6513         if (num_of_uri == ORIGINAL_URI_ONLY) {
6514                 /* audio looping path */
6515                 if (count >= REPEAT_COUNT_MIN) {
6516                         /* decrease play count */
6517                         /* we succeeded to rewind. update play count and then wait for next EOS */
6518                         count--;
6519                         mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6520                 } else if (count != REPEAT_COUNT_INFINITE) {
6521                         LOGD("there is no next uri and no repeat");
6522                         goto ERROR;
6523                 }
6524                 LOGD("looping cnt %d", count);
6525         } else {
6526                 /* gapless playback path */
6527                 if (!__mmplayer_get_next_uri(player)) {
6528                         LOGE("failed to get next uri");
6529                         goto ERROR;
6530                 }
6531         }
6532         return TRUE;
6533
6534 ERROR:
6535         LOGE("unable to play gapless path. EOS will be posted soon");
6536         return FALSE;
6537 }
6538
6539 static void
6540 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6541 {
6542         GstPad *sinkpad = g_value_get_object (item);
6543         GstElement *element = GST_ELEMENT(user_data);
6544         if (!sinkpad || !element) {
6545                 LOGE("invalid parameter");
6546                 return;
6547         }
6548
6549         LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6550         gst_element_release_request_pad(element, GST_PAD(sinkpad));
6551 }
6552
6553 static gboolean
6554 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6555 {
6556         mmplayer_gst_element_t *sinkbin = NULL;
6557         main_element_id_e concatId = MMPLAYER_M_NUM;
6558         main_element_id_e sinkId = MMPLAYER_M_NUM;
6559         gboolean send_notice = FALSE;
6560         GstElement *element;
6561         GstIterator *iter;
6562
6563         MMPLAYER_FENTER();
6564         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6565
6566         LOGD("type %d", type);
6567
6568         switch (type) {
6569         case MM_PLAYER_TRACK_TYPE_AUDIO:
6570                 concatId = MMPLAYER_M_A_CONCAT;
6571                 sinkId = MMPLAYER_A_BIN;
6572                 sinkbin = player->pipeline->audiobin;
6573                 break;
6574         case MM_PLAYER_TRACK_TYPE_VIDEO:
6575                 concatId = MMPLAYER_M_V_CONCAT;
6576                 sinkId = MMPLAYER_V_BIN;
6577                 sinkbin = player->pipeline->videobin;
6578                 send_notice = TRUE;
6579                 break;
6580         case MM_PLAYER_TRACK_TYPE_TEXT:
6581                 concatId = MMPLAYER_M_T_CONCAT;
6582                 sinkId = MMPLAYER_T_BIN;
6583                 sinkbin = player->pipeline->textbin;
6584                 break;
6585         default:
6586                 LOGE("requested type is not supportable");
6587                 return FALSE;
6588                 break;
6589         }
6590
6591         element = player->pipeline->mainbin[concatId].gst;
6592         if (!element)
6593                 return TRUE;
6594
6595         if ((sinkbin) && (sinkbin[sinkId].gst)) {
6596                 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6597                 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6598                 if (srcpad && sinkpad) {
6599                         /* after getting drained signal there is no data flows, so no need to do pad_block */
6600                         LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6601                         gst_pad_unlink(srcpad, sinkpad);
6602
6603                         /* send custom event to sink pad to handle it at video sink */
6604                         if (send_notice) {
6605                                 LOGD("send custom event to sinkpad");
6606                                 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6607                                 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6608                                 gst_pad_send_event(sinkpad, event);
6609                         }
6610                 }
6611                 gst_object_unref(srcpad);
6612                 gst_object_unref(sinkpad);
6613         }
6614
6615         LOGD("release concat request pad");
6616         /* release and unref requests pad from the selector */
6617         iter = gst_element_iterate_sink_pads(element);
6618         while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6619                 gst_iterator_resync(iter);
6620         gst_iterator_free(iter);
6621
6622         return TRUE;
6623 }
6624
6625 static gboolean
6626 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6627 {
6628         mmplayer_track_t *selector = &player->track[type];
6629         mmplayer_gst_element_t *sinkbin = NULL;
6630         main_element_id_e selectorId = MMPLAYER_M_NUM;
6631         main_element_id_e sinkId = MMPLAYER_M_NUM;
6632         GstPad *srcpad = NULL;
6633         GstPad *sinkpad = NULL;
6634         gboolean send_notice = FALSE;
6635
6636         MMPLAYER_FENTER();
6637         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6638
6639         LOGD("type %d", type);
6640
6641         switch (type) {
6642         case MM_PLAYER_TRACK_TYPE_AUDIO:
6643                 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6644                 sinkId = MMPLAYER_A_BIN;
6645                 sinkbin = player->pipeline->audiobin;
6646                 break;
6647         case MM_PLAYER_TRACK_TYPE_VIDEO:
6648                 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6649                 sinkId = MMPLAYER_V_BIN;
6650                 sinkbin = player->pipeline->videobin;
6651                 send_notice = TRUE;
6652                 break;
6653         case MM_PLAYER_TRACK_TYPE_TEXT:
6654                 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6655                 sinkId = MMPLAYER_T_BIN;
6656                 sinkbin = player->pipeline->textbin;
6657                 break;
6658         default:
6659                 LOGE("requested type is not supportable");
6660                 return FALSE;
6661                 break;
6662         }
6663
6664         if (player->pipeline->mainbin[selectorId].gst) {
6665                 gint n;
6666
6667                 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6668
6669                 if (selector->event_probe_id != 0)
6670                         gst_pad_remove_probe(srcpad, selector->event_probe_id);
6671                 selector->event_probe_id = 0;
6672
6673                 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6674                         sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6675
6676                         if (srcpad && sinkpad) {
6677                                 /* after getting drained signal there is no data flows, so no need to do pad_block */
6678                                 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6679                                 gst_pad_unlink(srcpad, sinkpad);
6680
6681                                 /* send custom event to sink pad to handle it at video sink */
6682                                 if (send_notice) {
6683                                         LOGD("send custom event to sinkpad");
6684                                         GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6685                                         GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6686                                         gst_pad_send_event(sinkpad, event);
6687                                 }
6688                         }
6689
6690                         gst_object_unref(sinkpad);
6691                         sinkpad = NULL;
6692                 }
6693                 gst_object_unref(srcpad);
6694                 srcpad = NULL;
6695
6696                 LOGD("selector release");
6697
6698                 /* release and unref requests pad from the selector */
6699                 for (n = 0; n < selector->streams->len; n++) {
6700                         GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6701                         gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6702                 }
6703
6704                 g_ptr_array_set_size(selector->streams, 0);
6705
6706                 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6707                 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6708
6709                 player->pipeline->mainbin[selectorId].gst = NULL;
6710                 selector = NULL;
6711         }
6712
6713         return TRUE;
6714 }
6715
6716 static void
6717 __mmplayer_deactivate_old_path(mmplayer_t *player)
6718 {
6719         MMPLAYER_FENTER();
6720         MMPLAYER_RETURN_IF_FAIL(player);
6721
6722         if (MMPLAYER_USE_DECODEBIN(player)) {
6723                 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6724                         (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6725                         (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6726                         LOGE("deactivate selector error");
6727                         goto ERROR;
6728                 }
6729         } else {
6730                 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6731                         (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6732                         (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6733                         LOGE("deactivate concat error");
6734                         goto ERROR;
6735                 }
6736         }
6737
6738         _mmplayer_track_destroy(player);
6739         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6740
6741         if (player->streamer) {
6742                 _mm_player_streaming_initialize(player->streamer, FALSE);
6743                 _mm_player_streaming_destroy(player->streamer);
6744                 player->streamer = NULL;
6745         }
6746
6747         MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6748         MMPLAYER_FLEAVE();
6749         return;
6750
6751 ERROR:
6752
6753         if (!player->msg_posted) {
6754                 MMMessageParamType msg = {0,};
6755
6756                 /*post error*/
6757                 msg.code = MM_ERROR_PLAYER_INTERNAL;
6758                 LOGE("gapless_uri_play> deactivate error");
6759
6760                 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6761                 player->msg_posted = TRUE;
6762         }
6763         return;
6764 }
6765
6766 int
6767 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6768 {
6769         int result = MM_ERROR_NONE;
6770         mmplayer_t *player = (mmplayer_t *)hplayer;
6771         MMPLAYER_FENTER();
6772
6773         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6774         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6775
6776         if (mm_player_set_attribute(hplayer, NULL,
6777                         "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6778                 LOGE("failed to set attribute");
6779                 result = MM_ERROR_PLAYER_INTERNAL;
6780         } else {
6781                 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6782                         LOGE("failed to add the original uri in the uri list.");
6783         }
6784
6785         MMPLAYER_FLEAVE();
6786         return result;
6787 }
6788
6789 int
6790 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6791 {
6792         mmplayer_t *player = (mmplayer_t *)hplayer;
6793         guint num_of_list = 0;
6794
6795         MMPLAYER_FENTER();
6796
6797         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6798         MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6799
6800         if (player->pipeline && player->pipeline->textbin) {
6801                 LOGE("subtitle path is enabled.");
6802                 return MM_ERROR_PLAYER_INVALID_STATE;
6803         }
6804
6805         num_of_list = g_list_length(player->uri_info.uri_list);
6806
6807         if (is_first_path) {
6808                 if (num_of_list == 0) {
6809                         player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6810                         SECURE_LOGD("add original path : %s", uri);
6811                 } else {
6812                         g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6813                         player->uri_info.uri_list = g_list_prepend(
6814                                 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6815                         SECURE_LOGD("change original path : %s", uri);
6816                 }
6817         } else {
6818                 MMHandleType attrs = 0;
6819                 attrs = MMPLAYER_GET_ATTRS(player);
6820
6821                 if (num_of_list == 0) {
6822                         char *original_uri = NULL;
6823
6824                         if (attrs) {
6825                                 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6826
6827                                 if (!original_uri) {
6828                                         LOGE("there is no original uri.");
6829                                         return MM_ERROR_PLAYER_INVALID_STATE;
6830                                 }
6831
6832                                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6833                                 player->uri_info.uri_idx = 0;
6834
6835                                 SECURE_LOGD("add original path at first : %s", original_uri);
6836                         }
6837                 }
6838
6839                 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6840                 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6841         }
6842
6843         MMPLAYER_FLEAVE();
6844         return MM_ERROR_NONE;
6845 }
6846
6847 int
6848 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6849 {
6850         mmplayer_t *player = (mmplayer_t *)hplayer;
6851         char *next_uri = NULL;
6852         guint num_of_list = 0;
6853
6854         MMPLAYER_FENTER();
6855         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6856
6857         num_of_list = g_list_length(player->uri_info.uri_list);
6858
6859         if (num_of_list > 0) {
6860                 gint uri_idx = player->uri_info.uri_idx;
6861
6862                 if (uri_idx < num_of_list - 1)
6863                         uri_idx++;
6864                 else
6865                         uri_idx = 0;
6866
6867                 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6868                 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6869
6870                 *uri = g_strdup(next_uri);
6871         }
6872
6873         MMPLAYER_FLEAVE();
6874         return MM_ERROR_NONE;
6875 }
6876
6877 void
6878 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6879         GstCaps *caps, gpointer data)
6880 {
6881         mmplayer_t *player = (mmplayer_t *)data;
6882         const gchar *klass = NULL;
6883         const gchar *mime = NULL;
6884         gchar *caps_str = NULL;
6885
6886         klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6887         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6888         caps_str = gst_caps_to_string(caps);
6889
6890         LOGW("unknown type of caps : %s from %s",
6891                                         caps_str, GST_ELEMENT_NAME(elem));
6892
6893         MMPLAYER_FREEIF(caps_str);
6894
6895         /* There is no available codec. */
6896         __mmplayer_check_not_supported_codec(player, klass, mime);
6897 }
6898
6899 gboolean
6900 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6901         GstCaps *caps, gpointer data)
6902 {
6903         mmplayer_t *player = (mmplayer_t *)data;
6904         const char *mime = NULL;
6905         gboolean ret = TRUE;
6906
6907         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6908         mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6909
6910         if (g_str_has_prefix(mime, "audio")) {
6911                 GstStructure *caps_structure = NULL;
6912                 gint samplerate = 0;
6913                 gint channels = 0;
6914                 gchar *caps_str = NULL;
6915
6916                 caps_structure = gst_caps_get_structure(caps, 0);
6917                 gst_structure_get_int(caps_structure, "rate", &samplerate);
6918                 gst_structure_get_int(caps_structure, "channels", &channels);
6919
6920                 if ((channels > 0 && samplerate == 0)) {
6921                         LOGD("exclude audio...");
6922                         ret = FALSE;
6923                 }
6924
6925                 caps_str = gst_caps_to_string(caps);
6926                 /* set it directly because not sent by TAG */
6927                 if (g_strrstr(caps_str, "mobile-xmf"))
6928                         mm_player_set_attribute((MMHandleType)player, NULL,
6929                                         "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6930
6931                 MMPLAYER_FREEIF(caps_str);
6932         } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6933                 LOGD("already video linked");
6934                 ret = FALSE;
6935         } else {
6936                 LOGD("found new stream");
6937         }
6938
6939         return ret;
6940 }
6941
6942 static gboolean
6943 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6944 {
6945         gboolean ret = FALSE;
6946         GDBusConnection *conn = NULL;
6947         GError *err = NULL;
6948         GVariant *result = NULL;
6949         const gchar *dbus_device_type = NULL;
6950         const gchar *dbus_ret = NULL;
6951         gint idx = 0;
6952
6953         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6954         if (!conn || err) {
6955                 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6956                 g_error_free(err);
6957                 goto DONE;
6958         }
6959
6960         result = g_dbus_connection_call_sync(conn,
6961                                         "org.pulseaudio.Server",
6962                                         "/org/pulseaudio/StreamManager",
6963                                         "org.pulseaudio.StreamManager",
6964                                         "GetCurrentMediaRoutingPath",
6965                                         g_variant_new("(s)", "out"),
6966                                         G_VARIANT_TYPE("(ss)"),
6967                                         G_DBUS_CALL_FLAGS_NONE,
6968                                         2000,
6969                                         NULL,
6970                                         &err);
6971         if (!result || err) {
6972                 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6973                 g_error_free(err);
6974                 goto DONE;
6975         }
6976
6977         /* device type is listed in stream-map.json at mmfw-sysconf */
6978         g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6979
6980         LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6981         if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6982                 goto DONE;
6983
6984         /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6985         for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6986                 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6987                         LOGD("audio offload is supportable");
6988                         ret = TRUE;
6989                         goto DONE;
6990                 }
6991         }
6992
6993         LOGD("audio offload is not supportable");
6994
6995 DONE:
6996         g_variant_unref(result);
6997         if (conn)
6998                 g_object_unref(conn);
6999
7000         return ret;
7001 }
7002
7003 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7004 {
7005         mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7006         gint64 position = 0;
7007
7008         MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7009                 player->pipeline && player->pipeline->mainbin);
7010
7011         MMPLAYER_CMD_LOCK(player);
7012         current_state = MMPLAYER_CURRENT_STATE(player);
7013
7014         if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7015                 LOGW("getting current position failed in paused");
7016
7017         _mmplayer_unrealize((MMHandleType)player);
7018         _mmplayer_realize((MMHandleType)player);
7019
7020         _mmplayer_set_position((MMHandleType)player, position);
7021
7022         /* async not to be blocked in streaming case */
7023         mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7024
7025         _mmplayer_pause((MMHandleType)player);
7026
7027         if (current_state == MM_PLAYER_STATE_PLAYING)
7028                 _mmplayer_start((MMHandleType)player);
7029         MMPLAYER_CMD_UNLOCK(player);
7030
7031         LOGD("rebuilding audio pipeline is completed.");
7032 }
7033
7034 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7035 {
7036         mmplayer_t *player = (mmplayer_t *)user_data;
7037         mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7038         gboolean is_supportable = FALSE;
7039
7040         if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7041                 LOGW("failed to get device type");
7042         else
7043                 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7044
7045         if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7046                 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7047                 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7048                 LOGD("ignore this dev connected info");
7049                 return;
7050         }
7051
7052         is_supportable = __mmplayer_is_audio_offload_device_type(player);
7053         if (player->build_audio_offload == is_supportable) {
7054                 LOGD("keep current pipeline without re-building");
7055                 return;
7056         }
7057
7058         /* rebuild pipeline */
7059         LOGD("re-build pipeline - offload: %d", is_supportable);
7060         player->build_audio_offload = FALSE;
7061         __mmplayer_rebuild_audio_pipeline(player);
7062
7063         return;
7064 }
7065
7066 static gboolean
7067 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7068 {
7069         unsigned int id = 0;
7070
7071         if (player->audio_device_cb_id != 0) {
7072                 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7073                 return TRUE;
7074         }
7075
7076         if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7077                                 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7078                 LOGD("added device connected cb (%u)", id);
7079                 player->audio_device_cb_id = id;
7080         } else {
7081                 LOGW("failed to add device connected cb");
7082                 return FALSE;
7083         }
7084
7085         return TRUE;
7086 }
7087
7088 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7089 {
7090         mmplayer_t *player = (mmplayer_t *)hplayer;
7091
7092         MMPLAYER_FENTER();
7093         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7094         MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7095
7096         *activated = player->build_audio_offload;
7097
7098         LOGD("offload activated : %d", (int)*activated);
7099
7100         MMPLAYER_FLEAVE();
7101         return MM_ERROR_NONE;
7102 }
7103
7104 static gboolean
7105 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7106 {
7107         /* NOTE :
7108            this function need to be updated according to the supported media format
7109            @see player->ini.audio_offload_media_format */
7110
7111         if (__mmplayer_is_only_mp3_type(player->type)) {
7112                 LOGD("offload supportable media format type");
7113                 return TRUE;
7114         }
7115
7116         return FALSE;
7117 }
7118
7119 static gboolean
7120 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7121 {
7122         gboolean ret = FALSE;
7123         GstElementFactory *factory = NULL;
7124
7125         MMPLAYER_FENTER();
7126         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7127
7128         LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7129         if (!__mmplayer_is_offload_supported_type(player))
7130                 goto DONE;
7131
7132         if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7133                 LOGD("there is no audio offload sink");
7134                 goto DONE;
7135         }
7136
7137         if (player->ini.audio_offload_device_type[0][0] == '\0') {
7138                 LOGW("there is no audio device type to support offload");
7139                 goto DONE;
7140         }
7141
7142         factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7143         if (!factory) {
7144                 LOGW("there is no installed audio offload sink element");
7145                 goto DONE;
7146         }
7147         gst_object_unref(factory);
7148
7149         if (_mmplayer_acquire_hw_resource(player,
7150                         MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7151                 LOGE("failed to acquire audio offload decoder resource");
7152                 goto DONE;
7153         }
7154
7155         if (!__mmplayer_add_audio_device_connected_cb(player))
7156                 goto DONE;
7157
7158         if (!__mmplayer_is_audio_offload_device_type(player))
7159                 goto DONE;
7160
7161         LOGD("audio offload can be built");
7162         ret = TRUE;
7163
7164 DONE:
7165         if (!ret)
7166                 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7167
7168         MMPLAYER_FLEAVE();
7169         return ret;
7170 }
7171
7172 static GstAutoplugSelectResult
7173 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7174 {
7175         GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7176         int audio_offload = 0;
7177
7178         if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7179                 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7180
7181                 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7182                         LOGD("expose audio path to build offload output path");
7183                         player->build_audio_offload = TRUE;
7184                         /* update codec info */
7185                         player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7186                         player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7187                         player->audiodec_linked = 1;
7188
7189                         ret = GST_AUTOPLUG_SELECT_EXPOSE;
7190                         goto DONE;
7191                 }
7192
7193                 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7194                                   And need to consider the multi-track audio content.
7195                           There is no HW audio decoder in public. */
7196
7197                 /* set stream information */
7198                 if (!player->audiodec_linked)
7199                         _mmplayer_set_audio_attrs(player, caps);
7200
7201                 /* update codec info */
7202                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7203                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7204                 player->audiodec_linked = 1;
7205
7206         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7207
7208                 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7209                         (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7210
7211                         /* mark video decoder for acquire */
7212                         if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7213                                 LOGW("video decoder resource is already acquired, skip it.");
7214                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7215                                 goto DONE;
7216                         }
7217
7218                         if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7219                                 LOGE("failed to acquire video decoder resource");
7220                                 ret = GST_AUTOPLUG_SELECT_SKIP;
7221                                 goto DONE;
7222                         }
7223                         player->interrupted_by_resource = FALSE;
7224                 }
7225
7226                 /* update codec info */
7227                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7228                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7229                 player->videodec_linked = 1;
7230         }
7231
7232 DONE:
7233         return ret;
7234 }
7235
7236 GValueArray *
7237 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7238                 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7239 {
7240 #define DEFAULT_IDX 0xFFFF
7241 #define MIN_FACTORY_NUM 2
7242         mmplayer_t *player = (mmplayer_t *)data;
7243         GValueArray *new_factories = NULL;
7244         GValue val = { 0, };
7245         GstElementFactory *factory = NULL;
7246         const gchar *klass = NULL;
7247         gchar *factory_name = NULL;
7248         guint hw_dec_idx = DEFAULT_IDX;
7249         guint first_sw_dec_idx = DEFAULT_IDX;
7250         guint last_sw_dec_idx = DEFAULT_IDX;
7251         guint new_pos = DEFAULT_IDX;
7252         guint rm_pos = DEFAULT_IDX;
7253         int audio_codec_type;
7254         int video_codec_type;
7255         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7256
7257         if (factories->n_values < MIN_FACTORY_NUM)
7258                 return NULL;
7259
7260         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7261         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7262
7263 #ifdef __DEBUG__
7264         LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7265 #endif
7266         for (int i = 0 ; i < factories->n_values ; i++) {
7267                 gchar *hw_dec_info = NULL;
7268                 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7269
7270                 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7271                 if (!factory) {
7272                         LOGW("failed to get factory object");
7273                         continue;
7274                 }
7275                 klass = gst_element_factory_get_klass(factory);
7276                 factory_name = GST_OBJECT_NAME(factory);
7277
7278 #ifdef __DEBUG__
7279                 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7280 #endif
7281                 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7282                         if (!player->need_audio_dec_sorting) {
7283                                 LOGD("sorting is not required");
7284                                 return NULL;
7285                         }
7286                         codec_type = audio_codec_type;
7287                         hw_dec_info = player->ini.audiocodec_element_hw;
7288                         sw_dec_info = player->ini.audiocodec_element_sw;
7289                 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7290                         if (!player->need_video_dec_sorting) {
7291                                 LOGD("sorting is not required");
7292                                 return NULL;
7293                         }
7294                         codec_type = video_codec_type;
7295                         hw_dec_info = player->ini.videocodec_element_hw;
7296                         sw_dec_info = player->ini.videocodec_element_sw;
7297                 } else {
7298                         continue;
7299                 }
7300
7301                 if (g_strrstr(factory_name, hw_dec_info)) {
7302                         hw_dec_idx = i;
7303                 } else {
7304                         for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7305                                 if (strstr(factory_name, sw_dec_info[j])) {
7306                                         last_sw_dec_idx = i;
7307                                         if (first_sw_dec_idx == DEFAULT_IDX) {
7308                                                 first_sw_dec_idx = i;
7309                                         }
7310                                 }
7311                         }
7312
7313                         if (first_sw_dec_idx == DEFAULT_IDX)
7314                                 LOGW("unknown codec %s", factory_name);
7315                 }
7316         }
7317
7318         if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7319                 return NULL;
7320
7321         if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7322                 if (hw_dec_idx < first_sw_dec_idx)
7323                         return NULL;
7324                 new_pos = first_sw_dec_idx;
7325                 rm_pos = hw_dec_idx + 1;
7326         } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7327                 if (last_sw_dec_idx < hw_dec_idx)
7328                         return NULL;
7329                 new_pos = last_sw_dec_idx + 1;
7330                 rm_pos = hw_dec_idx;
7331         } else {
7332                 return NULL;
7333         }
7334
7335         /* change position - insert H/W decoder according to the new position */
7336         factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7337         if (!factory) {
7338                 LOGW("failed to get factory object");
7339                 return NULL;
7340         }
7341         new_factories = g_value_array_copy(factories);
7342         g_value_init (&val, G_TYPE_OBJECT);
7343         g_value_set_object (&val, factory);
7344         g_value_array_insert(new_factories, new_pos, &val);
7345         g_value_unset (&val);
7346         g_value_array_remove(new_factories, rm_pos);    /* remove previous H/W element */
7347
7348         for (int i = 0 ; i < new_factories->n_values ; i++) {
7349                 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7350                 if (factory)
7351                         LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7352                                 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7353                 else
7354                         LOGE("[Re-arranged] failed to get factory object");
7355         }
7356
7357         return new_factories;
7358 }
7359
7360 gint
7361 _mmplayer_gst_decode_autoplug_select(GstElement *bin,  GstPad *pad,
7362         GstCaps *caps, GstElementFactory *factory, gpointer data)
7363 {
7364         GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7365         mmplayer_t *player = (mmplayer_t *)data;
7366
7367         gchar *factory_name = NULL;
7368         gchar *caps_str = NULL;
7369         const gchar *klass = NULL;
7370         gint idx = 0;
7371
7372         factory_name = GST_OBJECT_NAME(factory);
7373         klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7374         caps_str = gst_caps_to_string(caps);
7375
7376         LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7377
7378         /* store type string */
7379         if (player->type == NULL) {
7380                 player->type = gst_caps_to_string(caps);
7381                 __mmplayer_update_content_type_info(player);
7382         }
7383
7384         /* filtering exclude keyword */
7385         for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7386                 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7387                         LOGW("skipping [%s] by exclude keyword [%s]",
7388                                         factory_name, player->ini.exclude_element_keyword[idx]);
7389
7390                         result = GST_AUTOPLUG_SELECT_SKIP;
7391                         goto DONE;
7392                 }
7393         }
7394
7395         for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7396                 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7397                         LOGW("skipping [%s] by unsupported codec keyword [%s]",
7398                                 factory_name, player->ini.unsupported_codec_keyword[idx]);
7399                         result = GST_AUTOPLUG_SELECT_SKIP;
7400                         goto DONE;
7401                 }
7402         }
7403
7404         /* exclude webm format */
7405         /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7406          * because webm format is not supportable.
7407          * If webm is disabled in "autoplug-continue", there is no state change
7408          * failure or error because the decodebin will expose the pad directly.
7409          * It make MSL invoke _prepare_async_callback.
7410          * So, we need to disable webm format in "autoplug-select" */
7411         if (caps_str && strstr(caps_str, "webm")) {
7412                 LOGW("webm is not supported");
7413                 result = GST_AUTOPLUG_SELECT_SKIP;
7414                 goto DONE;
7415         }
7416
7417         /* check factory class for filtering */
7418         /* NOTE : msl don't need to use image plugins.
7419          * So, those plugins should be skipped for error handling.
7420          */
7421         if (g_strrstr(klass, "Codec/Decoder/Image")) {
7422                 LOGD("skipping [%s] by not required", factory_name);
7423                 result = GST_AUTOPLUG_SELECT_SKIP;
7424                 goto DONE;
7425         }
7426
7427         if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7428                 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7429                 // TO CHECK : subtitle if needed, add subparse exception.
7430                 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7431                 result = GST_AUTOPLUG_SELECT_SKIP;
7432                 goto DONE;
7433         }
7434
7435         if (g_strrstr(factory_name, "mpegpsdemux")) {
7436                 LOGD("skipping PS container - not support");
7437                 result = GST_AUTOPLUG_SELECT_SKIP;
7438                 goto DONE;
7439         }
7440
7441         if (g_strrstr(factory_name, "mssdemux"))
7442                 player->smooth_streaming = TRUE;
7443
7444         if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7445                 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7446                 gint stype = 0;
7447                 gint width = 0;
7448                 GstStructure *str = NULL;
7449                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7450
7451                 /* don't make video because of not required */
7452                 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7453                         (!player->set_mode.video_export)) {
7454                         LOGD("no need video decoding, expose pad");
7455                         result = GST_AUTOPLUG_SELECT_EXPOSE;
7456                         goto DONE;
7457                 }
7458
7459                 /* get w/h for omx state-tune */
7460                 /* FIXME: deprecated? */
7461                 str = gst_caps_get_structure(caps, 0);
7462                 gst_structure_get_int(str, "width", &width);
7463
7464                 if (width != 0) {
7465                         if (player->v_stream_caps) {
7466                                 gst_caps_unref(player->v_stream_caps);
7467                                 player->v_stream_caps = NULL;
7468                         }
7469
7470                         player->v_stream_caps = gst_caps_copy(caps);
7471                         LOGD("take caps for video state tune");
7472                         MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7473                 }
7474         }
7475
7476         if (g_strrstr(klass, "Codec/Decoder")) {
7477                 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7478                 if (result != GST_AUTOPLUG_SELECT_TRY) {
7479                         LOGW("skip add decoder");
7480                         goto DONE;
7481                 }
7482         }
7483
7484 DONE:
7485         MMPLAYER_FREEIF(caps_str);
7486
7487         return result;
7488 }
7489
7490 void
7491 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7492         gpointer data)
7493 {
7494         int ret = MM_ERROR_NONE;
7495         mmplayer_t *player = (mmplayer_t *)data;
7496         mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7497         mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7498         gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7499
7500         MMPLAYER_FENTER();
7501         MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7502
7503         LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7504
7505         if (MMPLAYER_USE_DECODEBIN(player))
7506                 return;
7507
7508         if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7509                 return;
7510
7511         ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7512         if (ret != MM_ERROR_NONE) {
7513                 LOGE("fail to change state to NULL");
7514                 return;
7515         }
7516
7517         ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7518         if (ret != MM_ERROR_NONE) {
7519                 LOGE("fail to change state to NULL");
7520                 return;
7521         }
7522
7523         if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7524                 LOGE("failed to remove video concat");
7525         }
7526
7527         if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7528                 LOGE("failed to remove videobin");
7529         }
7530
7531         gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7532         mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7533         mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7534
7535         gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7536         MMPLAYER_FREEIF(player->pipeline->videobin);
7537
7538         ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7539         if (ret != MM_ERROR_NONE)
7540                 LOGE("failed to release overlay resources");
7541
7542         player->videodec_linked = 0;
7543
7544         MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7545         MMPLAYER_FLEAVE();
7546 }
7547
7548 void
7549 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7550 {
7551         mmplayer_t *player = (mmplayer_t *)data;
7552
7553         MMPLAYER_FENTER();
7554         MMPLAYER_RETURN_IF_FAIL(player);
7555
7556         LOGD("got about to finish signal");
7557
7558         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7559                 LOGW("Fail to get cmd lock");
7560                 return;
7561         }
7562
7563         if (!__mmplayer_verify_gapless_play_path(player)) {
7564                 LOGD("decoding is finished.");
7565                 MMPLAYER_CMD_UNLOCK(player);
7566                 return;
7567         }
7568
7569         _mmplayer_set_reconfigure_state(player, TRUE);
7570         MMPLAYER_CMD_UNLOCK(player);
7571
7572         MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7573         __mmplayer_deactivate_old_path(player);
7574
7575         MMPLAYER_FLEAVE();
7576 }
7577
7578 void
7579 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7580 {
7581         mmplayer_t *player = (mmplayer_t *)data;
7582         GstIterator *iter = NULL;
7583         GValue item = { 0, };
7584         GstPad *pad = NULL;
7585         gboolean done = FALSE;
7586         gboolean is_all_drained = TRUE;
7587
7588         MMPLAYER_FENTER();
7589         MMPLAYER_RETURN_IF_FAIL(player);
7590
7591         LOGD("got drained signal");
7592
7593         if (!MMPLAYER_CMD_TRYLOCK(player)) {
7594                 LOGW("Fail to get cmd lock");
7595                 return;
7596         }
7597
7598         if (!__mmplayer_verify_gapless_play_path(player)) {
7599                 LOGD("decoding is finished.");
7600                 MMPLAYER_CMD_UNLOCK(player);
7601                 return;
7602         }
7603
7604         _mmplayer_set_reconfigure_state(player, TRUE);
7605         MMPLAYER_CMD_UNLOCK(player);
7606
7607         /* check decodebin src pads whether they received EOS or not */
7608         iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7609
7610         while (!done) {
7611                 switch (gst_iterator_next(iter, &item)) {
7612                 case GST_ITERATOR_OK:
7613                         pad = g_value_get_object(&item);
7614                         if (pad && !GST_PAD_IS_EOS(pad)) {
7615                                 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7616                                 is_all_drained = FALSE;
7617                                 break;
7618                         }
7619                         g_value_reset(&item);
7620                         break;
7621                 case GST_ITERATOR_RESYNC:
7622                         gst_iterator_resync(iter);
7623                         break;
7624                 case GST_ITERATOR_ERROR:
7625                 case GST_ITERATOR_DONE:
7626                         done = TRUE;
7627                         break;
7628                 }
7629         }
7630         g_value_unset(&item);
7631         gst_iterator_free(iter);
7632
7633         if (!is_all_drained) {
7634                 LOGD("Wait util the all pads get EOS.");
7635                 MMPLAYER_FLEAVE();
7636                 return;
7637         }
7638
7639         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7640         player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7641
7642         /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7643         MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7644         __mmplayer_deactivate_old_path(player);
7645
7646         MMPLAYER_FLEAVE();
7647 }
7648
7649 void
7650 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7651 {
7652         mmplayer_t *player = (mmplayer_t *)data;
7653         const gchar *klass = NULL;
7654         gchar *factory_name = NULL;
7655
7656         klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7657         factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7658
7659         LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7660
7661         if (__mmplayer_add_dump_buffer_probe(player, element))
7662                 LOGD("add buffer probe");
7663
7664         if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7665                 gchar *selected = NULL;
7666                 selected = g_strdup(GST_ELEMENT_NAME(element));
7667                 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7668
7669                 /* update codec info */
7670                 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7671                 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7672                 player->audiodec_linked = 1;
7673         } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7674                 /* update codec info */
7675                 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7676                 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7677                 player->videodec_linked = 1;
7678         }
7679
7680         if (g_strrstr(klass, "Demuxer/Adaptive")) {
7681                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7682                 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7683
7684                 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7685                                                 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7686
7687                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7688                                                 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7689                                                 "max-video-width", player->adaptive_info.limit.width,
7690                                                 "max-video-height", player->adaptive_info.limit.height, NULL);
7691
7692         } else if (g_strrstr(klass, "Demuxer")) {
7693 #ifdef __DEBUG__
7694                 LOGD("plugged element is demuxer. take it");
7695 #endif
7696                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7697                 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7698         } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7699                 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7700                 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7701         }
7702
7703         if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7704                 int surface_type = 0;
7705
7706                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7707         }
7708
7709         // to support trust-zone only
7710         if (g_strrstr(factory_name, "asfdemux")) {
7711                 LOGD("set file-location %s", player->profile.uri);
7712                 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7713         } else if (g_strrstr(factory_name, "legacyh264parse")) {
7714                 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7715                 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7716         } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7717                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7718                         (__mmplayer_is_only_mp3_type(player->type))) {
7719                         LOGD("[mpegaudioparse] set streaming pull mode.");
7720                         g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7721                 }
7722         } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7723                 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7724         } else if (g_strrstr(factory_name, "omxdec_h264")) {
7725                 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7726                 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7727                         g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7728                         LOGD("Send SPS and PPS Insertion every IDR frame");
7729                 }
7730         }
7731
7732         if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7733                 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7734                 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7735
7736                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7737                 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7738
7739                 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7740                         (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7741                         (MMPLAYER_IS_DASH_STREAMING(player))) {
7742                         /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7743                         _mm_player_streaming_set_multiqueue(player->streamer, element);
7744                         _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7745                 }
7746
7747         }
7748
7749         return;
7750 }
7751
7752 static void
7753 __mmplayer_release_misc(mmplayer_t *player)
7754 {
7755         int i;
7756         bool cur_mode = player->set_mode.rich_audio;
7757         MMPLAYER_FENTER();
7758
7759         MMPLAYER_RETURN_IF_FAIL(player);
7760
7761         player->sent_bos = FALSE;
7762         player->playback_rate = DEFAULT_PLAYBACK_RATE;
7763
7764         player->seek_state = MMPLAYER_SEEK_NONE;
7765
7766         player->total_bitrate = 0;
7767         player->total_maximum_bitrate = 0;
7768
7769         player->not_found_demuxer = 0;
7770
7771         player->last_position = 0;
7772         player->duration = 0;
7773         player->http_content_size = 0;
7774         player->not_supported_codec = MISSING_PLUGIN_NONE;
7775         player->can_support_codec = FOUND_PLUGIN_NONE;
7776         player->pending_seek.is_pending = false;
7777         player->pending_seek.pos = 0;
7778         player->msg_posted = FALSE;
7779         player->has_many_types = FALSE;
7780         player->is_subtitle_force_drop = FALSE;
7781         player->play_subtitle = FALSE;
7782         player->adjust_subtitle_pos = 0;
7783         player->has_closed_caption = FALSE;
7784         player->set_mode.video_export = false;
7785         player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7786         memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7787         /* recover mode */
7788         player->set_mode.rich_audio = cur_mode;
7789
7790         if (player->audio_device_cb_id > 0 &&
7791                 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7792                 LOGW("failed to remove audio device_connected_callback");
7793         player->audio_device_cb_id = 0;
7794
7795         for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7796                 player->bitrate[i] = 0;
7797                 player->maximum_bitrate[i] = 0;
7798         }
7799
7800         /* free memory related to audio effect */
7801         MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7802
7803         if (player->adaptive_info.var_list) {
7804                 g_list_free_full(player->adaptive_info.var_list, g_free);
7805                 player->adaptive_info.var_list = NULL;
7806         }
7807
7808         player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7809         player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7810         player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7811
7812         /* Reset video360 settings to their defaults in case if the pipeline is to be
7813          * re-created.
7814          * */
7815         player->video360_metadata.is_spherical = -1;
7816         player->is_openal_plugin_used = FALSE;
7817
7818         player->is_content_spherical = FALSE;
7819         player->is_video360_enabled = TRUE;
7820         player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7821         player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7822         player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7823         player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7824         player->video360_zoom = 1.0f;
7825         player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7826         player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7827
7828         player->sound.rg_enable = false;
7829
7830         __mmplayer_initialize_video_roi(player);
7831         MMPLAYER_FLEAVE();
7832 }
7833
7834 static void
7835 __mmplayer_release_misc_post(mmplayer_t *player)
7836 {
7837         gchar *original_uri = NULL;
7838         MMPLAYER_FENTER();
7839
7840         /* player->pipeline is already released before. */
7841         MMPLAYER_RETURN_IF_FAIL(player);
7842
7843         player->video_decoded_cb = NULL;
7844         player->video_decoded_cb_user_param = NULL;
7845         player->video_stream_prerolled = false;
7846
7847         player->audio_decoded_cb = NULL;
7848         player->audio_decoded_cb_user_param = NULL;
7849         player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7850
7851         player->audio_stream_changed_cb = NULL;
7852         player->audio_stream_changed_cb_user_param = NULL;
7853
7854         mm_player_set_attribute((MMHandleType)player, NULL,
7855                 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7856
7857         /* clean found audio decoders */
7858         if (player->audio_decoders) {
7859                 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7860                 player->audio_decoders = NULL;
7861         }
7862
7863         /* clean the uri list except original uri */
7864         if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7865                 GList *tmp = NULL;
7866                 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7867                 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7868                 g_list_free_full(tmp, (GDestroyNotify)g_free);
7869
7870                 if (!original_uri)
7871                         LOGW("failed to get original uri info");
7872
7873                 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7874                                 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7875                 MMPLAYER_FREEIF(original_uri);
7876         }
7877
7878         /* clear the audio stream buffer list */
7879         _mmplayer_audio_stream_clear_buffer(player, FALSE);
7880
7881         /* clear the video stream bo list */
7882         __mmplayer_video_stream_destroy_bo_list(player);
7883         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7884
7885         if (player->profile.input_mem.buf) {
7886                 free(player->profile.input_mem.buf);
7887                 player->profile.input_mem.buf = NULL;
7888         }
7889         player->profile.input_mem.len = 0;
7890         player->profile.input_mem.offset = 0;
7891
7892         player->uri_info.uri_idx = 0;
7893         MMPLAYER_FLEAVE();
7894 }
7895
7896 gboolean
7897 __mmplayer_check_subtitle(mmplayer_t *player)
7898 {
7899         MMHandleType attrs = 0;
7900         char *subtitle_uri = NULL;
7901
7902         MMPLAYER_FENTER();
7903
7904         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7905
7906         /* get subtitle attribute */
7907         attrs = MMPLAYER_GET_ATTRS(player);
7908         if (!attrs)
7909                 return FALSE;
7910
7911         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7912         if (!subtitle_uri || !strlen(subtitle_uri))
7913                 return FALSE;
7914
7915         SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7916         player->is_external_subtitle_present = TRUE;
7917
7918         MMPLAYER_FLEAVE();
7919
7920         return TRUE;
7921 }
7922
7923 void
7924 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7925 {
7926         MMPLAYER_RETURN_IF_FAIL(player);
7927
7928         if (player->eos_timer) {
7929                 LOGD("cancel eos timer");
7930                 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7931                 player->eos_timer = 0;
7932         }
7933
7934         return;
7935 }
7936
7937 static void
7938 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7939 {
7940         MMPLAYER_FENTER();
7941
7942         MMPLAYER_RETURN_IF_FAIL(player);
7943         MMPLAYER_RETURN_IF_FAIL(sink);
7944
7945         if (first)
7946                 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7947         else
7948                 player->sink_elements = g_list_append(player->sink_elements, sink);
7949
7950         MMPLAYER_FLEAVE();
7951 }
7952
7953 static void
7954 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7955 {
7956         MMPLAYER_FENTER();
7957
7958         MMPLAYER_RETURN_IF_FAIL(player);
7959         MMPLAYER_RETURN_IF_FAIL(sink);
7960
7961         player->sink_elements = g_list_remove(player->sink_elements, sink);
7962
7963         MMPLAYER_FLEAVE();
7964 }
7965
7966 void
7967 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7968         mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7969 {
7970         mmplayer_signal_item_t *item = NULL;
7971
7972         MMPLAYER_FENTER();
7973         MMPLAYER_RETURN_IF_FAIL(player);
7974
7975         if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7976                 LOGE("invalid signal type [%d]", type);
7977                 return;
7978         }
7979
7980         item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7981         if (!item) {
7982                 LOGE("cannot connect signal [%s]", signal);
7983                 return;
7984         }
7985
7986         item->obj = object;
7987         item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7988         player->signals[type] = g_list_append(player->signals[type], item);
7989
7990         MMPLAYER_FLEAVE();
7991         return;
7992 }
7993
7994 /* NOTE : be careful with calling this api. please refer to below glib comment
7995  * glib comment : Note that there is a bug in GObject that makes this function much
7996  * less useful than it might seem otherwise. Once gobject is disposed, the callback
7997  * will no longer be called, but, the signal handler is not currently disconnected.
7998  * If the instance is itself being freed at the same time than this doesn't matter,
7999  * since the signal will automatically be removed, but if instance persists,
8000  * then the signal handler will leak. You should not remove the signal yourself
8001  * because in a future versions of GObject, the handler will automatically be
8002  * disconnected.
8003  *
8004  * It's possible to work around this problem in a way that will continue to work
8005  * with future versions of GObject by checking that the signal handler is still
8006  * connected before disconnected it:
8007  *
8008  *  if (g_signal_handler_is_connected(instance, id))
8009  *    g_signal_handler_disconnect(instance, id);
8010  */
8011 static void
8012 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8013 {
8014         GList *sig_list = NULL;
8015         mmplayer_signal_item_t *item = NULL;
8016
8017         MMPLAYER_FENTER();
8018
8019         MMPLAYER_RETURN_IF_FAIL(player);
8020
8021         LOGD("release signals type : %d", type);
8022
8023         if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8024                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8025                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8026                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8027                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8028                 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8029                 return;
8030         }
8031
8032         sig_list = player->signals[type];
8033
8034         for (; sig_list; sig_list = sig_list->next) {
8035                 item = sig_list->data;
8036
8037                 if (item && item->obj) {
8038                         if (g_signal_handler_is_connected(item->obj, item->sig))
8039                                 g_signal_handler_disconnect(item->obj, item->sig);
8040                 }
8041
8042                 MMPLAYER_FREEIF(item);
8043         }
8044
8045         g_list_free(player->signals[type]);
8046         player->signals[type] = NULL;
8047
8048         MMPLAYER_FLEAVE();
8049
8050         return;
8051 }
8052
8053 int
8054 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8055 {
8056         mmplayer_t *player = 0;
8057         int prev_display_surface_type = 0;
8058
8059         MMPLAYER_FENTER();
8060
8061         MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8062
8063         player = MM_PLAYER_CAST(handle);
8064
8065         /* check video sinkbin is created */
8066         if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8067                 LOGW("Videosink is already created");
8068                 return MM_ERROR_NONE;
8069         }
8070
8071         LOGD("videosink element is not yet ready");
8072
8073         if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8074                 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8075                 MMPLAYER_FLEAVE();
8076                 return MM_ERROR_INVALID_ARGUMENT;
8077         }
8078
8079         /* load previous attributes */
8080         if (player->attrs) {
8081                 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8082                 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8083                 if (prev_display_surface_type == surface_type) {
8084                         LOGD("incoming display surface type is same as previous one, do nothing..");
8085                         MMPLAYER_FLEAVE();
8086                         return MM_ERROR_NONE;
8087                 }
8088         } else {
8089                 LOGE("failed to load attributes");
8090                 MMPLAYER_FLEAVE();
8091                 return MM_ERROR_PLAYER_INTERNAL;
8092         }
8093
8094         /* videobin is not created yet, so we just set attributes related to display surface */
8095         LOGD("store display attribute for given surface type(%d)", surface_type);
8096         mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8097                         "display_overlay", wl_surface_id, NULL);
8098
8099         MMPLAYER_FLEAVE();
8100         return MM_ERROR_NONE;
8101 }
8102
8103 /* Note : if silent is true, then subtitle would not be displayed. :*/
8104 int
8105 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8106 {
8107         mmplayer_t *player = (mmplayer_t *)hplayer;
8108
8109         MMPLAYER_FENTER();
8110
8111         /* check player handle */
8112         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8113
8114         player->set_mode.subtitle_off = silent;
8115
8116         LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8117
8118         MMPLAYER_FLEAVE();
8119
8120         return MM_ERROR_NONE;
8121 }
8122
8123 int
8124 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8125 {
8126         mmplayer_gst_element_t *mainbin = NULL;
8127         mmplayer_gst_element_t *textbin = NULL;
8128         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8129         GstState current_state = GST_STATE_VOID_PENDING;
8130         GstState element_state = GST_STATE_VOID_PENDING;
8131         GstState element_pending_state = GST_STATE_VOID_PENDING;
8132         gint64 time = 0;
8133         GstEvent *event = NULL;
8134         int result = MM_ERROR_NONE;
8135
8136         GstClock *curr_clock = NULL;
8137         GstClockTime base_time, start_time, curr_time;
8138
8139
8140         MMPLAYER_FENTER();
8141
8142         /* check player handle */
8143         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8144                                                                 player->pipeline &&
8145                                                                 player->pipeline->mainbin &&
8146                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8147
8148         mainbin = player->pipeline->mainbin;
8149         textbin = player->pipeline->textbin;
8150
8151         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8152
8153         // sync clock with current pipeline
8154         curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8155         curr_time = gst_clock_get_time(curr_clock);
8156
8157         base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8158         start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8159
8160         LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8161                 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8162
8163         if (current_state > GST_STATE_READY) {
8164                 // sync state with current pipeline
8165                 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8166                 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8167                 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8168
8169                 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8170                 if (GST_STATE_CHANGE_FAILURE == ret) {
8171                         LOGE("fail to state change.");
8172                         result = MM_ERROR_PLAYER_INTERNAL;
8173                         goto ERROR;
8174                 }
8175         }
8176         gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8177         gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8178
8179         if (curr_clock) {
8180                 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8181                 gst_object_unref(curr_clock);
8182         }
8183
8184         // seek to current position
8185         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8186                 result = MM_ERROR_PLAYER_INVALID_STATE;
8187                 LOGE("gst_element_query_position failed, invalid state");
8188                 goto ERROR;
8189         }
8190
8191         LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8192         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);
8193         if (event) {
8194                 _mmplayer_gst_send_event_to_sink(player, event);
8195         } else {
8196                 result = MM_ERROR_PLAYER_INTERNAL;
8197                 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8198                 goto ERROR;
8199         }
8200
8201         /* sync state with current pipeline */
8202         gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8203         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8204         gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8205
8206         return MM_ERROR_NONE;
8207
8208 ERROR:
8209         /* release text pipeline resource */
8210         player->textsink_linked = 0;
8211
8212         /* release signal */
8213         __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8214
8215         /* release textbin with it's children */
8216         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8217         MMPLAYER_FREEIF(player->pipeline->textbin);
8218         player->pipeline->textbin = NULL;
8219
8220         /* release subtitle elem */
8221         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8222         MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8223
8224         return result;
8225 }
8226
8227 static int
8228 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8229 {
8230         GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8231         GstState current_state = GST_STATE_VOID_PENDING;
8232
8233         MMHandleType attrs = 0;
8234         mmplayer_gst_element_t *mainbin = NULL;
8235         mmplayer_gst_element_t *textbin = NULL;
8236
8237         gchar *subtitle_uri = NULL;
8238         int result = MM_ERROR_NONE;
8239         const gchar *charset = NULL;
8240
8241         MMPLAYER_FENTER();
8242
8243         /* check player handle */
8244         MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8245                                                                 player->pipeline &&
8246                                                                 player->pipeline->mainbin &&
8247                                                                 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8248         MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8249
8250         mainbin = player->pipeline->mainbin;
8251         textbin = player->pipeline->textbin;
8252
8253         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8254         if (current_state < GST_STATE_READY) {
8255                 result = MM_ERROR_PLAYER_INVALID_STATE;
8256                 LOGE("Pipeline is not in proper state");
8257                 goto EXIT;
8258         }
8259
8260         attrs = MMPLAYER_GET_ATTRS(player);
8261         if (!attrs) {
8262                 LOGE("cannot get content attribute");
8263                 result = MM_ERROR_PLAYER_INTERNAL;
8264                 goto EXIT;
8265         }
8266
8267         mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8268         if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8269                 LOGE("subtitle uri is not proper filepath");
8270                 result = MM_ERROR_PLAYER_INVALID_URI;
8271                 goto EXIT;
8272         }
8273
8274         if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8275                 LOGE("failed to get storage info of subtitle path");
8276                 result = MM_ERROR_PLAYER_INVALID_URI;
8277                 goto EXIT;
8278         }
8279
8280         SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8281         SECURE_LOGD("new subtitle file path is [%s]", filepath);
8282
8283         if (!strcmp(filepath, subtitle_uri)) {
8284                 LOGD("subtitle path is not changed");
8285                 goto EXIT;
8286         } else {
8287                 if (mm_player_set_attribute((MMHandleType)player, NULL,
8288                                 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8289                         LOGE("failed to set attribute");
8290                         goto EXIT;
8291                 }
8292         }
8293
8294         //gst_pad_set_blocked_async(src-srcpad, TRUE)
8295         MMPLAYER_SUBTITLE_INFO_LOCK(player);
8296         player->subtitle_language_list = NULL;
8297         MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8298
8299         ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8300         if (ret != GST_STATE_CHANGE_SUCCESS) {
8301                 LOGE("failed to change state of textbin to READY");
8302                 result = MM_ERROR_PLAYER_INTERNAL;
8303                 goto EXIT;
8304         }
8305
8306         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8307         if (ret != GST_STATE_CHANGE_SUCCESS) {
8308                 LOGE("failed to change state of subparse to READY");
8309                 result = MM_ERROR_PLAYER_INTERNAL;
8310                 goto EXIT;
8311         }
8312
8313         ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8314         if (ret != GST_STATE_CHANGE_SUCCESS) {
8315                 LOGE("failed to change state of filesrc to READY");
8316                 result = MM_ERROR_PLAYER_INTERNAL;
8317                 goto EXIT;
8318         }
8319
8320         __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8321
8322         g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8323
8324         charset = _mmplayer_get_charset(filepath);
8325         if (charset) {
8326                 LOGD("detected charset is %s", charset);
8327                 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8328         }
8329
8330         result = _mmplayer_sync_subtitle_pipeline(player);
8331
8332 EXIT:
8333         MMPLAYER_FLEAVE();
8334         return result;
8335 }
8336
8337 /* API to switch between external subtitles */
8338 int
8339 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8340 {
8341         int result = MM_ERROR_NONE;
8342         mmplayer_t *player = (mmplayer_t *)hplayer;
8343         char *path = NULL;
8344
8345         MMPLAYER_FENTER();
8346
8347         /* check player handle */
8348         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8349
8350         /* filepath can be null in idle state */
8351         if (filepath) {
8352                 /* check file path */
8353                 if ((path = strstr(filepath, "file://")))
8354                         result = _mmplayer_exist_file_path(path + 7);
8355                 else
8356                         result = _mmplayer_exist_file_path(filepath);
8357
8358                 if (result != MM_ERROR_NONE) {
8359                         LOGE("invalid subtitle path 0x%X", result);
8360                         return result; /* file not found or permission denied */
8361                 }
8362         }
8363
8364         if (!player->pipeline) {
8365                 /* IDLE state */
8366                 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8367                                 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8368                         LOGE("failed to set attribute");
8369                         return MM_ERROR_PLAYER_INTERNAL;
8370                 }
8371         } else {
8372                 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8373                 /* check filepath */
8374                 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8375
8376                 if (!__mmplayer_check_subtitle(player)) {
8377                         if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8378                                         filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8379                                 LOGE("failed to set attribute");
8380                                 return MM_ERROR_PLAYER_INTERNAL;
8381                         }
8382
8383                         if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8384                                 LOGE("fail to create text pipeline");
8385                                 return MM_ERROR_PLAYER_INTERNAL;
8386                         }
8387
8388                         result = _mmplayer_sync_subtitle_pipeline(player);
8389                 } else {
8390                         result = __mmplayer_change_external_subtitle_language(player, filepath);
8391                 }
8392
8393                 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8394                 player->is_external_subtitle_added_now = TRUE;
8395
8396                 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8397                 if (!player->subtitle_language_list) {
8398                         gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8399                         if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8400                                 LOGW("subtitle language list is not updated yet");
8401                 }
8402                 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8403         }
8404
8405         MMPLAYER_FLEAVE();
8406         return result;
8407 }
8408
8409 static int
8410 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8411 {
8412         guint active_idx = 0;
8413         GstStream *stream = NULL;
8414         GList *streams = NULL;
8415         GstCaps *caps = NULL;
8416
8417         MMPLAYER_FENTER();
8418         LOGD("Switching Streams... type: %d, index: %d", type, index);
8419
8420         player->track[type].active_track_index = index;
8421
8422         for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8423                 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8424                 LOGD("track type:%d, total: %d, active: %d", i,
8425                                 player->track[i].total_track_num, player->track[i].active_track_index);
8426                 if (player->track[i].total_track_num > 0 &&
8427                         player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8428                         active_idx = player->track[i].active_track_index;
8429                         stream = g_ptr_array_index(player->track[i].streams, active_idx);
8430                         streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8431                         LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8432
8433                         if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8434                                 caps = gst_stream_get_caps(stream);
8435                                 if (caps) {
8436                                         _mmplayer_set_audio_attrs(player, caps);
8437                                         gst_caps_unref(caps);
8438                                 }
8439                         }
8440                 }
8441         }
8442
8443         if (streams) {
8444                 LOGD("send select stream event");
8445                 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8446                                 gst_event_new_select_streams(streams));
8447                 g_list_free(streams);
8448         }
8449
8450         MMPLAYER_FLEAVE();
8451         return MM_ERROR_NONE;
8452 }
8453
8454 static int
8455 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8456 {
8457         int result = MM_ERROR_NONE;
8458         gchar *change_pad_name = NULL;
8459         GstPad *sinkpad = NULL;
8460         mmplayer_gst_element_t *mainbin = NULL;
8461         main_element_id_e elem_idx = MMPLAYER_M_NUM;
8462         GstCaps *caps = NULL;
8463         gint total_track_num = 0;
8464
8465         MMPLAYER_FENTER();
8466
8467         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8468                                                                                                         MM_ERROR_PLAYER_NOT_INITIALIZED);
8469
8470         LOGD("Change Track(%d) to %d", type, index);
8471
8472         mainbin = player->pipeline->mainbin;
8473
8474         if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8475                 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8476         } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8477                 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8478         } else {
8479                 /* Changing Video Track is not supported. */
8480                 LOGE("Track Type Error");
8481                 goto EXIT;
8482         }
8483
8484         if (mainbin[elem_idx].gst == NULL) {
8485                 result = MM_ERROR_PLAYER_NO_OP;
8486                 LOGD("Req track doesn't exist");
8487                 goto EXIT;
8488         }
8489
8490         total_track_num = player->track[type].total_track_num;
8491         if (total_track_num <= 0) {
8492                 result = MM_ERROR_PLAYER_NO_OP;
8493                 LOGD("Language list is not available");
8494                 goto EXIT;
8495         }
8496
8497         if ((index < 0) || (index >= total_track_num)) {
8498                 result = MM_ERROR_INVALID_ARGUMENT;
8499                 LOGD("Not a proper index : %d", index);
8500                 goto EXIT;
8501         }
8502
8503         /*To get the new pad from the selector*/
8504         change_pad_name = g_strdup_printf("sink_%u", index);
8505         if (change_pad_name == NULL) {
8506                 result = MM_ERROR_PLAYER_INTERNAL;
8507                 LOGD("Pad does not exists");
8508                 goto EXIT;
8509         }
8510
8511         LOGD("new active pad name: %s", change_pad_name);
8512
8513         sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8514         if (sinkpad == NULL) {
8515                 LOGD("sinkpad is NULL");
8516                 result = MM_ERROR_PLAYER_INTERNAL;
8517                 goto EXIT;
8518         }
8519
8520         LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8521         g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8522
8523         caps = gst_pad_get_current_caps(sinkpad);
8524         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8525
8526         if (sinkpad)
8527                 gst_object_unref(sinkpad);
8528
8529         if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8530                 _mmplayer_set_audio_attrs(player, caps);
8531
8532         if (caps)
8533                 gst_caps_unref(caps);
8534
8535 EXIT:
8536         MMPLAYER_FREEIF(change_pad_name);
8537         return result;
8538 }
8539
8540 int
8541 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8542 {
8543         int result = MM_ERROR_NONE;
8544         mmplayer_t *player = NULL;
8545         mmplayer_gst_element_t *mainbin = NULL;
8546
8547         gint current_active_index = 0;
8548
8549         GstState current_state = GST_STATE_VOID_PENDING;
8550         gint64 time = 0;
8551
8552         MMPLAYER_FENTER();
8553
8554         player = (mmplayer_t *)hplayer;
8555         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556
8557         if (!player->pipeline) {
8558                 LOGE("Track %d pre setting -> %d", type, index);
8559
8560                 player->track[type].active_track_index = index;
8561                 goto EXIT;
8562         }
8563
8564         mainbin = player->pipeline->mainbin;
8565
8566         current_active_index = player->track[type].active_track_index;
8567
8568         /*If index is same as running index no need to change the pad*/
8569         if (current_active_index == index)
8570                 goto EXIT;
8571
8572         if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8573                 result = MM_ERROR_PLAYER_INVALID_STATE;
8574                 goto EXIT;
8575         }
8576
8577         current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8578         if (current_state < GST_STATE_PAUSED) {
8579                 result = MM_ERROR_PLAYER_INVALID_STATE;
8580                 LOGW("Pipeline not in proper state");
8581                 goto EXIT;
8582         }
8583
8584         if (MMPLAYER_USE_DECODEBIN(player))
8585                 result = __mmplayer_change_selector_pad(player, type, index);
8586         else
8587                 result = __mmplayer_switch_stream(player, type, index);
8588
8589         if (result != MM_ERROR_NONE) {
8590                 LOGE("failed to change track");
8591                 goto EXIT;
8592         }
8593
8594         player->track[type].active_track_index = index;
8595
8596         if (MMPLAYER_USE_DECODEBIN(player)) {
8597                 GstEvent *event = NULL;
8598                 if (current_state == GST_STATE_PLAYING) {
8599                         event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8600                                 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8601                                 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8602                         if (event) {
8603                                 _mmplayer_gst_send_event_to_sink(player, event);
8604                         } else {
8605                                 result = MM_ERROR_PLAYER_INTERNAL;
8606                                 goto EXIT;
8607                         }
8608                 }
8609         }
8610
8611 EXIT:
8612         return result;
8613 }
8614
8615 int
8616 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8617 {
8618         mmplayer_t *player = (mmplayer_t *)hplayer;
8619
8620         MMPLAYER_FENTER();
8621
8622         /* check player handle */
8623         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8624
8625         *silent = player->set_mode.subtitle_off;
8626
8627         LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8628
8629         MMPLAYER_FLEAVE();
8630
8631         return MM_ERROR_NONE;
8632 }
8633
8634 static gboolean
8635 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8636 {
8637         MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8638         MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8639
8640         gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8641         gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8642
8643         int idx = 0;
8644
8645         for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8646                 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8647                         LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8648                         mmplayer_dump_t *dump_s;
8649                         dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8650                         if (dump_s == NULL) {
8651                                 LOGE("malloc fail");
8652                                 return FALSE;
8653                         }
8654
8655                         dump_s->dump_element_file = NULL;
8656                         dump_s->dump_pad = NULL;
8657                         dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8658
8659                         if (dump_s->dump_pad) {
8660                                 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8661                                 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]);
8662                                 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8663                                 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);
8664                                 /* add list for removed buffer probe and close FILE */
8665                                 player->dump_list = g_list_append(player->dump_list, dump_s);
8666                                 LOGD("%s sink pad added buffer probe for dump", factory_name);
8667                                 return TRUE;
8668                         } else {
8669                                 MMPLAYER_FREEIF(dump_s);
8670                                 LOGE("failed to get %s sink pad added", factory_name);
8671                         }
8672                 }
8673         }
8674         return FALSE;
8675 }
8676
8677 static GstPadProbeReturn
8678 __mmplayer_dump_buffer_probe_cb(GstPad *pad,  GstPadProbeInfo *info, gpointer u_data)
8679 {
8680         FILE *dump_data = (FILE *)u_data;
8681 //      int written = 0;
8682         GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8683         GstMapInfo probe_info = GST_MAP_INFO_INIT;
8684
8685         MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8686
8687         gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8688 #ifdef __DEBUG__
8689         LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8690 #endif
8691         fwrite(probe_info.data, 1, probe_info.size , dump_data);
8692
8693         gst_buffer_unmap(buffer, &probe_info);
8694
8695         return GST_PAD_PROBE_OK;
8696 }
8697
8698 static void
8699 __mmplayer_release_dump_list(GList *dump_list)
8700 {
8701         GList *d_list = dump_list;
8702
8703         if (!d_list)
8704                 return;
8705
8706         for (; d_list; d_list = g_list_next(d_list)) {
8707                 mmplayer_dump_t *dump_s = d_list->data;
8708                 if (dump_s->dump_pad) {
8709                         if (dump_s->probe_handle_id)
8710                                 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8711                         gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8712                 }
8713                 if (dump_s->dump_element_file) {
8714                         fclose(dump_s->dump_element_file);
8715                         dump_s->dump_element_file = NULL;
8716                 }
8717                 MMPLAYER_FREEIF(dump_s);
8718         }
8719         g_list_free(dump_list);
8720         dump_list = NULL;
8721 }
8722
8723 int
8724 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8725 {
8726         mmplayer_t *player = (mmplayer_t *)hplayer;
8727
8728         MMPLAYER_FENTER();
8729
8730         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731         MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8732
8733         *exist = (bool)player->has_closed_caption;
8734
8735         MMPLAYER_FLEAVE();
8736
8737         return MM_ERROR_NONE;
8738 }
8739
8740 void
8741 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8742 {
8743         MMPLAYER_FENTER();
8744         if (buffer) {
8745 #ifdef __DEBUG__
8746                 LOGD("unref internal gst buffer %p", buffer);
8747 #endif
8748                 gst_buffer_unref((GstBuffer *)buffer);
8749                 buffer = NULL;
8750         }
8751         MMPLAYER_FLEAVE();
8752 }
8753
8754 int
8755 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8756 {
8757         mmplayer_t *player = (mmplayer_t *)hplayer;
8758
8759         MMPLAYER_FENTER();
8760
8761         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8762         MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8763
8764         if (MMPLAYER_IS_STREAMING(player))
8765                 *timeout = (int)player->ini.live_state_change_timeout;
8766         else
8767                 *timeout = (int)player->ini.localplayback_state_change_timeout;
8768
8769         LOGD("timeout = %d", *timeout);
8770
8771         MMPLAYER_FLEAVE();
8772         return MM_ERROR_NONE;
8773 }
8774
8775 static void
8776 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8777 {
8778         int i = 0;
8779         MMPLAYER_FENTER();
8780         MMPLAYER_RETURN_IF_FAIL(player);
8781
8782         for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8783
8784                 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8785                         player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8786                         player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8787                         player->storage_info[i].id = -1;
8788                         memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8789
8790                         if (path_type != MMPLAYER_PATH_MAX)
8791                                 break;
8792                 }
8793         }
8794
8795         MMPLAYER_FLEAVE();
8796 }
8797
8798 int
8799 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8800 {
8801         int ret = MM_ERROR_NONE;
8802         mmplayer_t *player = (mmplayer_t *)hplayer;
8803         MMMessageParamType msg_param = {0, };
8804
8805         MMPLAYER_FENTER();
8806         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8807
8808         LOGW("state changed storage %d:%d", id, state);
8809
8810         if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8811                 return MM_ERROR_NONE;
8812
8813         /* FIXME: text path should be handled separately. */
8814         if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8815                 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8816                 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8817                 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8818                 LOGW("external storage is removed");
8819
8820                 if (player->msg_posted == FALSE) {
8821                         memset(&msg_param, 0, sizeof(MMMessageParamType));
8822                         msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8823                         MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8824                         player->msg_posted = TRUE;
8825                 }
8826
8827                 /* unrealize the player */
8828                 ret = _mmplayer_unrealize(hplayer);
8829                 if (ret != MM_ERROR_NONE)
8830                         LOGE("failed to unrealize");
8831         }
8832
8833         MMPLAYER_FLEAVE();
8834         return ret;
8835 }
8836
8837 int
8838 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8839 {
8840         int ret = MM_ERROR_NONE;
8841         mmplayer_t *player = (mmplayer_t *)hplayer;
8842         int idx = 0, total = 0;
8843         gchar *result = NULL, *tmp = NULL;
8844
8845         MMPLAYER_FENTER();
8846         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8847         MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8848
8849         total = *num = g_list_length(player->adaptive_info.var_list);
8850         if (total <= 0) {
8851                 LOGW("There is no stream variant info.");
8852                 return ret;
8853         }
8854
8855         result = g_strdup("");
8856         for (idx = 0 ; idx < total ; idx++) {
8857                 stream_variant_t *v_data = NULL;
8858                 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8859
8860                 if (v_data) {
8861                         gchar data[64] = {0};
8862                         snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8863
8864                         tmp = g_strconcat(result, data, NULL);
8865                         g_free(result);
8866                         result = tmp;
8867                 } else {
8868                         LOGW("There is no variant data in %d", idx);
8869                         (*num)--;
8870                 }
8871         }
8872
8873         *var_info = (char *)result;
8874
8875         LOGD("variant info %d:%s", *num, *var_info);
8876         MMPLAYER_FLEAVE();
8877         return ret;
8878 }
8879
8880 int
8881 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8882 {
8883         int ret = MM_ERROR_NONE;
8884         mmplayer_t *player = (mmplayer_t *)hplayer;
8885
8886         MMPLAYER_FENTER();
8887         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8888
8889         LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8890
8891         player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8892         player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8893         player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8894
8895         if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8896                 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8897                 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8898                                                 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8899
8900                 /* FIXME: seek to current position for applying new variant limitation */
8901         }
8902
8903         MMPLAYER_FLEAVE();
8904         return ret;
8905
8906 }
8907
8908 int
8909 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8910 {
8911         int ret = MM_ERROR_NONE;
8912         mmplayer_t *player = (mmplayer_t *)hplayer;
8913
8914         MMPLAYER_FENTER();
8915         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8916         MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8917
8918         *bandwidth = player->adaptive_info.limit.bandwidth;
8919         *width = player->adaptive_info.limit.width;
8920         *height = player->adaptive_info.limit.height;
8921
8922         LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8923
8924         MMPLAYER_FLEAVE();
8925         return ret;
8926 }
8927
8928 int
8929 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8930 {
8931         int ret = MM_ERROR_NONE;
8932         mmplayer_t *player = (mmplayer_t *)hplayer;
8933
8934         MMPLAYER_FENTER();
8935         MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8936         MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8937         MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8938
8939         *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8940
8941         if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8942                 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8943         else /* live case */
8944                 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8945
8946         LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8947
8948         MMPLAYER_FLEAVE();
8949         return ret;
8950 }
8951
8952 int
8953 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8954 {
8955 #define IDX_FIRST_SW_CODEC 0
8956         mmplayer_t *player = (mmplayer_t *)hplayer;
8957         int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8958         const char *attr_name = NULL;
8959         const char *default_type = NULL;
8960         const char *element_hw = NULL;
8961         const char *element_sw = NULL;
8962
8963         MMPLAYER_FENTER();
8964         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8965
8966         LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8967
8968         /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8969         switch (stream_type) {
8970         case MM_PLAYER_STREAM_TYPE_AUDIO:
8971                 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8972                 default_type = player->ini.audiocodec_default_type;
8973                 element_hw = player->ini.audiocodec_element_hw;
8974                 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8975                 break;
8976         case MM_PLAYER_STREAM_TYPE_VIDEO:
8977                 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8978                 default_type = player->ini.videocodec_default_type;
8979                 element_hw = player->ini.videocodec_element_hw;
8980                 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8981                 break;
8982         default:
8983                 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8984                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8985                 break;
8986         }
8987
8988         LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8989
8990         if (!strcmp(default_type, "sw"))
8991                 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8992         else
8993                 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8994
8995         if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8996                 codec_type = default_codec_type;
8997
8998         /* to support codec selection, codec info have to be added in ini file.
8999            in case of hw codec is selected, filter elements should be applied
9000            depending on the hw capabilities. */
9001         if (codec_type != default_codec_type) {
9002                 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9003                         ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9004                         LOGE("There is no codec for type %d", codec_type);
9005                         return MM_ERROR_PLAYER_NO_OP;
9006                 }
9007
9008                 LOGD("sorting is required");
9009                 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9010                         player->need_audio_dec_sorting = TRUE;
9011                 else
9012                         player->need_video_dec_sorting = TRUE;
9013         }
9014
9015         LOGD("update %s codec_type to %d", attr_name, codec_type);
9016         mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9017
9018         MMPLAYER_FLEAVE();
9019         return MM_ERROR_NONE;
9020 }
9021
9022 int
9023 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9024 {
9025         mmplayer_t *player = (mmplayer_t *)hplayer;
9026         GstElement *rg_vol_element = NULL;
9027
9028         MMPLAYER_FENTER();
9029
9030         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9031
9032         player->sound.rg_enable = enabled;
9033
9034         /* just hold rgvolume enable value if pipeline is not ready */
9035         if (!player->pipeline || !player->pipeline->audiobin) {
9036                 LOGD("pipeline is not ready. holding rgvolume enable value");
9037                 return MM_ERROR_NONE;
9038         }
9039
9040         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9041
9042         if (!rg_vol_element) {
9043                 LOGD("rgvolume element is not created");
9044                 return MM_ERROR_PLAYER_INTERNAL;
9045         }
9046
9047         if (enabled)
9048                 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9049         else
9050                 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9051
9052         MMPLAYER_FLEAVE();
9053
9054         return MM_ERROR_NONE;
9055 }
9056
9057 int
9058 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9059 {
9060         mmplayer_t *player = (mmplayer_t *)hplayer;
9061         GstElement *rg_vol_element = NULL;
9062         gboolean enable = FALSE;
9063
9064         MMPLAYER_FENTER();
9065
9066         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9067         MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9068
9069         /* just hold enable_rg value if pipeline is not ready */
9070         if (!player->pipeline || !player->pipeline->audiobin) {
9071                 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9072                 *enabled = player->sound.rg_enable;
9073                 return MM_ERROR_NONE;
9074         }
9075
9076         rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9077
9078         if (!rg_vol_element) {
9079                 LOGD("rgvolume element is not created");
9080                 return MM_ERROR_PLAYER_INTERNAL;
9081         }
9082
9083         g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9084         *enabled = (bool)enable;
9085
9086         MMPLAYER_FLEAVE();
9087
9088         return MM_ERROR_NONE;
9089 }
9090
9091 int
9092 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9093 {
9094         mmplayer_t *player = (mmplayer_t *)hplayer;
9095         MMHandleType attrs = 0;
9096         int handle = 0;
9097         int ret = MM_ERROR_NONE;
9098
9099         MMPLAYER_FENTER();
9100
9101         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9102
9103         attrs = MMPLAYER_GET_ATTRS(player);
9104         MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9105
9106         mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9107         if (!handle) {
9108                 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9109                 return MM_ERROR_PLAYER_INTERNAL;
9110         }
9111
9112         player->video_roi.scale_x = scale_x;
9113         player->video_roi.scale_y = scale_y;
9114         player->video_roi.scale_width = scale_width;
9115         player->video_roi.scale_height = scale_height;
9116
9117         /* check video sinkbin is created */
9118         if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9119                 return MM_ERROR_NONE;
9120
9121         if (!gst_video_overlay_set_video_roi_area(
9122                 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9123                 scale_x, scale_y, scale_width, scale_height))
9124                 ret = MM_ERROR_PLAYER_INTERNAL;
9125         else
9126                 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9127                         scale_x, scale_y, scale_width, scale_height);
9128
9129         MMPLAYER_FLEAVE();
9130
9131         return ret;
9132 }
9133
9134 int
9135 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9136 {
9137         mmplayer_t *player = (mmplayer_t *)hplayer;
9138         int ret = MM_ERROR_NONE;
9139
9140         MMPLAYER_FENTER();
9141
9142         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9143         MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9144
9145         *scale_x = player->video_roi.scale_x;
9146         *scale_y = player->video_roi.scale_y;
9147         *scale_width = player->video_roi.scale_width;
9148         *scale_height = player->video_roi.scale_height;
9149
9150         LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9151                 *scale_x, *scale_y, *scale_width, *scale_height);
9152
9153         return ret;
9154 }
9155
9156 int
9157 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9158 {
9159         mmplayer_t *player = (mmplayer_t *)hplayer;
9160
9161         MMPLAYER_FENTER();
9162
9163         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9164
9165         player->client_pid = pid;
9166
9167         LOGD("client pid[%d] %p", pid, player);
9168
9169         MMPLAYER_FLEAVE();
9170
9171         return MM_ERROR_NONE;
9172 }
9173
9174 int
9175 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9176 {
9177         mmplayer_t *player = (mmplayer_t *)hplayer;
9178         mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9179         enum audio_element_id elem_id = MMPLAYER_A_NUM;
9180
9181         MMPLAYER_FENTER();
9182
9183         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9184         MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9185
9186         *available = true;
9187         mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9188
9189         LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9190
9191         if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9192                 return MM_ERROR_NONE;
9193
9194         /* in case of audio codec default type is HW */
9195         switch(opt) {
9196                 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9197                         if (player->ini.support_audio_effect)
9198                                 return MM_ERROR_NONE;
9199                         elem_id = MMPLAYER_A_FILTER;
9200                 break;
9201                 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9202                         if (player->ini.support_replaygain_control)
9203                                 return MM_ERROR_NONE;
9204                         elem_id = MMPLAYER_A_RGVOL;
9205                 break;
9206                 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9207                         if (player->ini.support_pitch_control)
9208                                 return MM_ERROR_NONE;
9209                         elem_id = MMPLAYER_A_PITCH;
9210                 break;
9211                 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9212                         if (player->ini.support_audio_effect)
9213                                 return MM_ERROR_NONE;
9214                 break;
9215                 /* default case handling is not required */
9216         }
9217
9218         if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9219                 LOGW("audio control option [%d] is not available", opt);
9220                 *available = false;
9221         } else {
9222                 /* setting pcm exporting option is allowed before READY state */
9223                 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9224                         return MM_ERROR_PLAYER_INVALID_STATE;
9225
9226                 /* check whether the audio filter exist or not after READY state,
9227                    because the sw codec could be added during auto-plugging in some cases */
9228                 if (!player->pipeline ||
9229                         !player->pipeline->audiobin ||
9230                         !player->pipeline->audiobin[elem_id].gst) {
9231                         LOGW("there is no audio elem [%d]", elem_id);
9232                         *available = false;
9233                 }
9234         }
9235
9236         LOGD("audio control opt %d, available %d", opt, *available);
9237
9238         MMPLAYER_FLEAVE();
9239
9240         return MM_ERROR_NONE;
9241 }
9242
9243 static gboolean
9244 __mmplayer_update_duration_value(mmplayer_t *player)
9245 {
9246         gboolean ret = FALSE;
9247         gint64 dur_nsec = 0;
9248         LOGD("try to update duration");
9249
9250         if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9251                 player->duration = dur_nsec;
9252                 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9253                 ret = TRUE;
9254         }
9255
9256         if (player->duration < 0) {
9257                 LOGW("duration is Non-Initialized !!!");
9258                 player->duration = 0;
9259         }
9260
9261         /* update streaming service type */
9262         player->streaming_type =  _mmplayer_get_stream_service_type(player);
9263
9264         /* check duration is OK */
9265         if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9266                 /* FIXIT : find another way to get duration here. */
9267                 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9268
9269         return ret;
9270 }
9271
9272 static gboolean
9273 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9274 {
9275         /* update audio params
9276         NOTE : We need original audio params and it can be only obtained from src pad of audio
9277         decoder. Below code only valid when we are not using 'resampler' just before
9278         'audioconverter'. */
9279         GstCaps *caps_a = NULL;
9280         GstPad *pad = NULL;
9281         gint samplerate = 0, channels = 0;
9282         GstStructure *p = NULL;
9283         GstElement *aconv = NULL;
9284
9285         LOGD("try to update audio attrs");
9286
9287         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9288
9289         if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9290                 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9291         } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9292                 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9293         } else {
9294                 LOGE("there is no audio converter");
9295                 return FALSE;
9296         }
9297
9298         pad = gst_element_get_static_pad(aconv, "sink");
9299
9300         if (!pad) {
9301                 LOGW("failed to get pad from audio converter");
9302                 return FALSE;
9303         }
9304
9305         caps_a = gst_pad_get_current_caps(pad);
9306         if (!caps_a) {
9307                 LOGW("not ready to get audio caps");
9308                 gst_object_unref(pad);
9309                 return FALSE;
9310         }
9311
9312         p = gst_caps_get_structure(caps_a, 0);
9313
9314         mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9315
9316         gst_structure_get_int(p, "rate", &samplerate);
9317         gst_structure_get_int(p, "channels", &channels);
9318
9319         mm_player_set_attribute((MMHandleType)player, NULL,
9320                         "content_audio_samplerate", samplerate,
9321                         "content_audio_channels", channels, NULL);
9322
9323         SECURE_LOGD("samplerate : %d    channels : %d", samplerate, channels);
9324
9325         gst_caps_unref(caps_a);
9326         gst_object_unref(pad);
9327
9328         return TRUE;
9329 }
9330
9331 static gboolean
9332 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9333 {
9334         LOGD("try to update video attrs");
9335
9336         GstCaps *caps_v = NULL;
9337         GstPad *pad = NULL;
9338         gint tmpNu, tmpDe;
9339         gint width, height;
9340         GstStructure *p = NULL;
9341
9342         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9343         MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9344
9345         pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9346         if (!pad) {
9347                 LOGD("no videosink sink pad");
9348                 return FALSE;
9349         }
9350
9351         caps_v = gst_pad_get_current_caps(pad);
9352         /* Use v_stream_caps, if fail to get video_sink sink pad*/
9353         if (!caps_v && player->v_stream_caps) {
9354                 caps_v = player->v_stream_caps;
9355                 gst_caps_ref(caps_v);
9356         }
9357
9358         if (!caps_v) {
9359                 LOGD("no negotiated caps from videosink");
9360                 gst_object_unref(pad);
9361                 return FALSE;
9362         }
9363
9364         p = gst_caps_get_structure(caps_v, 0);
9365         gst_structure_get_int(p, "width", &width);
9366         gst_structure_get_int(p, "height", &height);
9367
9368         mm_player_set_attribute((MMHandleType)player, NULL,
9369                         MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9370
9371         gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9372
9373         SECURE_LOGD("width : %d     height : %d", width, height);
9374
9375         gst_caps_unref(caps_v);
9376         gst_object_unref(pad);
9377
9378         if (tmpDe > 0) {
9379                 mm_player_set_attribute((MMHandleType)player, NULL,
9380                                 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9381                 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9382         }
9383
9384         return TRUE;
9385 }
9386
9387 static gboolean
9388 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9389 {
9390         gboolean ret = FALSE;
9391         guint64 data_size = 0;
9392         gchar *path = NULL;
9393         struct stat sb;
9394
9395         /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9396         if (!player->duration)
9397                 return FALSE;
9398
9399         if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9400                 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9401                 if (stat(path, &sb) == 0)
9402                         data_size = (guint64)sb.st_size;
9403
9404         } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9405                 data_size = player->http_content_size;
9406         }
9407
9408         LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9409
9410         if (data_size) {
9411                 guint64 bitrate = 0;
9412                 guint64 msec_dur = 0;
9413
9414                 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9415                 if (msec_dur > 0) {
9416                         bitrate = data_size * 8 * 1000 / msec_dur;
9417                         SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9418                                         ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9419                         mm_player_set_attribute((MMHandleType)player, NULL,
9420                                         MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9421                         ret = TRUE;
9422                 } else {
9423                         LOGD("player duration is less than 0");
9424                 }
9425         }
9426
9427         if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9428                 if (player->total_bitrate) {
9429                         mm_player_set_attribute((MMHandleType)player, NULL,
9430                                         MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9431                         ret = TRUE;
9432                 }
9433         }
9434
9435         return ret;
9436 }
9437
9438 static void
9439 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9440 {
9441         strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9442         data->uri_type = uri_type;
9443 }
9444
9445 static int
9446 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9447 {
9448         int ret = MM_ERROR_PLAYER_INVALID_URI;
9449         int mem_size = 0;
9450         char *buffer = NULL;
9451         char *seperator = strchr(path, ',');
9452         char ext[100] = {0,}, size[100] = {0,};
9453
9454         if (seperator) {
9455                 if ((buffer = strstr(path, "ext="))) {
9456                         buffer += strlen("ext=");
9457
9458                         if (strlen(buffer)) {
9459                                 strncpy(ext, buffer, 99);
9460
9461                                 if ((seperator = strchr(ext, ','))
9462                                         || (seperator = strchr(ext, ' '))
9463                                         || (seperator = strchr(ext, '\0'))) {
9464                                         seperator[0] = '\0';
9465                                 }
9466                         }
9467                 }
9468
9469                 if ((buffer = strstr(path, "size="))) {
9470                         buffer += strlen("size=");
9471
9472                         if (strlen(buffer) > 0) {
9473                                 strncpy(size, buffer, 99);
9474
9475                                 if ((seperator = strchr(size, ','))
9476                                         || (seperator = strchr(size, ' '))
9477                                         || (seperator = strchr(size, '\0'))) {
9478                                         seperator[0] = '\0';
9479                                 }
9480
9481                                 mem_size = atoi(size);
9482                         }
9483                 }
9484         }
9485
9486         LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9487
9488         if (mem_size && param) {
9489                 if (data->input_mem.buf)
9490                         free(data->input_mem.buf);
9491                 data->input_mem.buf = malloc(mem_size);
9492
9493                 if (data->input_mem.buf) {
9494                         memcpy(data->input_mem.buf, param, mem_size);
9495                         data->input_mem.len = mem_size;
9496                         ret = MM_ERROR_NONE;
9497                 } else {
9498                         LOGE("failed to alloc mem %d", mem_size);
9499                         ret = MM_ERROR_PLAYER_INTERNAL;
9500                 }
9501
9502                 data->input_mem.offset = 0;
9503                 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9504         }
9505
9506         return ret;
9507 }
9508
9509 static int
9510 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9511 {
9512         gchar *location = NULL;
9513         GError *err = NULL;
9514         char *path = NULL;
9515         int ret = MM_ERROR_NONE;
9516
9517         if ((path = strstr(uri, "file://"))) {
9518                 location = g_filename_from_uri(uri, NULL, &err);
9519                 if (!location || (err != NULL)) {
9520                         LOGE("Invalid URI '%s' for filesrc: %s", path,
9521                                 (err != NULL) ? err->message : "unknown error");
9522                         if (err)
9523                                 g_error_free(err);
9524
9525                         MMPLAYER_FREEIF(location);
9526
9527                         data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9528                         return MM_ERROR_PLAYER_INVALID_URI;
9529                 }
9530                 LOGD("path from uri: %s", location);
9531         }
9532
9533         path = (location != NULL) ? (location) : ((char *)uri);
9534
9535
9536         ret = _mmplayer_exist_file_path(path);
9537
9538         /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9539         if (ret == MM_ERROR_NONE) {
9540                 if (_mmplayer_is_sdp_file(path)) {
9541                         LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9542                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9543                         data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9544                 } else {
9545                         g_snprintf(data->uri,  MM_MAX_URL_LEN, "file://%s", path);
9546                         data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9547                 }
9548         } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9549                 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9550         } else {
9551                 LOGE("invalid uri, could not play..");
9552                 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9553         }
9554
9555         MMPLAYER_FREEIF(location);
9556
9557         return ret;
9558 }
9559
9560 static mmplayer_video_decoded_data_info_t *
9561 __mmplayer_create_stream_from_pad(GstPad *pad)
9562 {
9563         GstCaps *caps = NULL;
9564         GstStructure *structure = NULL;
9565         unsigned int fourcc = 0;
9566         const gchar *string_format = NULL;
9567         mmplayer_video_decoded_data_info_t *stream = NULL;
9568         gint width, height;
9569         MMPixelFormatType format;
9570         GstVideoInfo info;
9571
9572         caps = gst_pad_get_current_caps(pad);
9573         if (!caps) {
9574                 LOGE("Caps is NULL.");
9575                 return NULL;
9576         }
9577
9578 #ifdef __DEBUG__
9579         MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9580 #endif
9581         structure = gst_caps_get_structure(caps, 0);
9582         gst_structure_get_int(structure, "width", &width);
9583         gst_structure_get_int(structure, "height", &height);
9584         string_format = gst_structure_get_string(structure, "format");
9585
9586         if (string_format)
9587                 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9588         format = _mmplayer_get_pixtype(fourcc);
9589         gst_video_info_from_caps(&info, caps);
9590         gst_caps_unref(caps);
9591
9592         /* moved here */
9593         if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9594                 LOGE("Wrong condition!!");
9595                 return NULL;
9596         }
9597
9598         stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9599         if (!stream) {
9600                 LOGE("failed to alloc mem for video data");
9601                 return NULL;
9602         }
9603
9604         stream->width = width;
9605         stream->height = height;
9606         stream->format = format;
9607         stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9608
9609         return stream;
9610 }
9611
9612 static void
9613 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9614 {
9615         unsigned int pitch = 0;
9616         unsigned int size = 0;
9617         int index = 0;
9618         tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9619         tbm_bo bo = NULL;
9620
9621         for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9622                 bo = gst_tizen_memory_get_bos(mem, index);
9623                 if (bo)
9624                         stream->bo[index] = tbm_bo_ref(bo);
9625                 else
9626                         LOGE("failed to get bo for index %d", index);
9627         }
9628
9629         for (index = 0; index < stream->plane_num; index++) {
9630                 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9631                 stream->stride[index] = pitch;
9632                 if (pitch)
9633                         stream->elevation[index] = size / pitch;
9634                 else
9635                         stream->elevation[index] = stream->height;
9636         }
9637 }
9638
9639 static gboolean
9640 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9641 {
9642         if (stream->format == MM_PIXEL_FORMAT_I420) {
9643                 int ret = TBM_SURFACE_ERROR_NONE;
9644                 tbm_surface_h surface;
9645                 tbm_surface_info_s info;
9646
9647                 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9648
9649                 ret = tbm_surface_get_info(surface, &info);
9650                 if (ret != TBM_SURFACE_ERROR_NONE) {
9651                         tbm_surface_destroy(surface);
9652                         return FALSE;
9653                 }
9654
9655                 tbm_surface_destroy(surface);
9656                 stream->stride[0] = info.planes[0].stride;
9657                 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9658                 stream->stride[1] = info.planes[1].stride;
9659                 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9660                 stream->stride[2] = info.planes[2].stride;
9661                 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9662                 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9663         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9664                 stream->stride[0] = stream->width * 4;
9665                 stream->elevation[0] = stream->height;
9666                 stream->bo_size = stream->stride[0] * stream->height;
9667         } else {
9668                 LOGE("Not support format %d", stream->format);
9669                 return FALSE;
9670         }
9671
9672         return TRUE;
9673 }
9674
9675 static gboolean
9676 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9677 {
9678         tbm_bo_handle thandle;
9679         gboolean is_mapped;
9680         int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9681         int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9682         int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9683         int i = 0;
9684         int j = 0;
9685         int k = 0;
9686         unsigned char *src = NULL;
9687         unsigned char *dest = NULL;
9688         GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9689
9690         is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9691         if (!is_mapped) {
9692                 LOGE("fail to gst_memory_map");
9693                 return FALSE;
9694         }
9695
9696         if (!mapinfo.data) {
9697                 LOGE("data pointer is wrong");
9698                 goto ERROR;
9699         }
9700
9701         stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9702         if (!stream->bo[0]) {
9703                 LOGE("Fail to tbm_bo_alloc!!");
9704                 goto ERROR;
9705         }
9706
9707         thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9708         if (!thandle.ptr) {
9709                 LOGE("thandle pointer is wrong");
9710                 goto ERROR;
9711         }
9712
9713         if (stream->format == MM_PIXEL_FORMAT_I420) {
9714                 src_stride[0] = GST_ROUND_UP_4(stream->width);
9715                 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9716                 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9717                 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9718
9719                 dest_offset[0] = 0;
9720                 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9721                 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9722
9723                 for (i = 0; i < 3; i++) {
9724                         src = mapinfo.data + src_offset[i];
9725                         dest = thandle.ptr + dest_offset[i];
9726
9727                         if (i > 0)
9728                                 k = 1;
9729
9730                         for (j = 0; j < stream->height >> k; j++) {
9731                                 memcpy(dest, src, stream->width>>k);
9732                                 src += src_stride[i];
9733                                 dest += stream->stride[i];
9734                         }
9735                 }
9736         } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9737                 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9738         } else {
9739                 LOGE("Not support format %d", stream->format);
9740                 goto ERROR;
9741         }
9742
9743         tbm_bo_unmap(stream->bo[0]);
9744         gst_memory_unmap(mem, &mapinfo);
9745
9746         return TRUE;
9747
9748 ERROR:
9749         if (stream->bo[0])
9750                 tbm_bo_unmap(stream->bo[0]);
9751
9752         if (is_mapped)
9753                 gst_memory_unmap(mem, &mapinfo);
9754
9755         return FALSE;
9756 }
9757
9758 static void
9759 __mmplayer_set_pause_state(mmplayer_t *player)
9760 {
9761         if (player->sent_bos)
9762                 return;
9763
9764         /* rtsp case, get content attrs by GstMessage */
9765         if (MMPLAYER_IS_RTSP_STREAMING(player))
9766                 return;
9767
9768         /* it's first time to update all content attrs. */
9769         _mmplayer_update_content_attrs(player, ATTR_ALL);
9770 }
9771
9772 static void
9773 __mmplayer_set_playing_state(mmplayer_t *player)
9774 {
9775         gchar *audio_codec = NULL;
9776
9777         if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9778                 /* initialize because auto resume is done well. */
9779                 player->resumed_by_rewind = FALSE;
9780                 player->playback_rate = 1.0;
9781         }
9782
9783         if (player->sent_bos)
9784                 return;
9785
9786         /* try to get content metadata */
9787
9788         /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9789          * c-api since c-api doesn't use _start() anymore. It may not work properly with
9790          * legacy mmfw-player api
9791          */
9792         _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9793
9794         if ((player->cmd == MMPLAYER_COMMAND_START)
9795                 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9796                 __mmplayer_handle_missed_plugin(player);
9797         }
9798
9799         /* check audio codec field is set or not
9800          * we can get it from typefinder or codec's caps.
9801          */
9802         mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9803
9804         /* The codec format can't be sent for audio only case like amr, mid etc.
9805          * Because, parser don't make related TAG.
9806          * So, if it's not set yet, fill it with found data.
9807          */
9808         if (!audio_codec) {
9809                 if (g_strrstr(player->type, "audio/midi"))
9810                         audio_codec = "MIDI";
9811                 else if (g_strrstr(player->type, "audio/x-amr"))
9812                         audio_codec = "AMR";
9813                 else if (g_strrstr(player->type, "audio/mpeg")
9814                                 && !g_strrstr(player->type, "mpegversion=(int)1"))
9815                         audio_codec = "AAC";
9816                 else
9817                         audio_codec = "unknown";
9818
9819                 if (mm_player_set_attribute((MMHandleType)player, NULL,
9820                                 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9821                         LOGE("failed to set attribute");
9822
9823                 LOGD("set audio codec type with caps");
9824         }
9825
9826         return;
9827 }