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