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