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