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